parent
e86694c57b
commit
7e9647b1ae
|
@ -12,6 +12,8 @@
|
||||||
- [qBittorrent](https://github.com/qbittorrent/qBittorrent)
|
- [qBittorrent](https://github.com/qbittorrent/qBittorrent)
|
||||||
- [Syncthing](https://github.com/syncthing/syncthing)
|
- [Syncthing](https://github.com/syncthing/syncthing)
|
||||||
- [National Weather Service](https://www.weather.gov/)
|
- [National Weather Service](https://www.weather.gov/)
|
||||||
|
- [Amcrest Cameras](https://amcrest.com/)
|
||||||
|
- [Infisical](https://infisical.com/)
|
||||||
|
|
||||||
## NATS Topics
|
## NATS Topics
|
||||||
|
|
||||||
|
|
|
@ -34,15 +34,15 @@ const (
|
||||||
HA_STATE_PREFIX = "homeassistant.states"
|
HA_STATE_PREFIX = "homeassistant.states"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Listen(parentLogger *slog.Logger, readme []byte) {
|
func Listen(parentLogger *slog.Logger, parentConfig *config.HatsConfig, readme []byte) {
|
||||||
logger = parentLogger
|
logger = parentLogger
|
||||||
|
cfg = parentConfig
|
||||||
|
|
||||||
// render readme to HTML
|
// render readme to HTML
|
||||||
p := parser.NewWithExtensions(parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock)
|
p := parser.NewWithExtensions(parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock)
|
||||||
doc := p.Parse(readme)
|
doc := p.Parse(readme)
|
||||||
homepage = string(markdown.Render(doc, html.NewRenderer(html.RendererOptions{Flags: html.CommonFlags | html.HrefTargetBlank})))
|
homepage = string(markdown.Render(doc, html.NewRenderer(html.RendererOptions{Flags: html.CommonFlags | html.HrefTargetBlank})))
|
||||||
|
|
||||||
cfg = config.FromEnvironment()
|
|
||||||
haClient = homeassistant.NewRestClient(cfg.GetHomeAssistantBaseUrl(), cfg.HomeAssistantToken)
|
haClient = homeassistant.NewRestClient(cfg.GetHomeAssistantBaseUrl(), cfg.HomeAssistantToken)
|
||||||
router := chi.NewRouter()
|
router := chi.NewRouter()
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,9 @@ func CloseSubscription() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Subscribe(parentLogger *slog.Logger) error {
|
func Subscribe(parentLogger *slog.Logger, parentConfig *config.HatsConfig) error {
|
||||||
logger = parentLogger
|
logger = parentLogger
|
||||||
cfg = config.FromEnvironment()
|
cfg = parentConfig
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
url := cfg.GetHomeAssistantWebsocketUrl()
|
url := cfg.GetHomeAssistantWebsocketUrl()
|
||||||
|
@ -72,7 +72,7 @@ func reconnect() {
|
||||||
time.Sleep(time.Duration(attempts) * 5 * time.Second)
|
time.Sleep(time.Duration(attempts) * 5 * time.Second)
|
||||||
logger.Info("Trying to reconnect to Home Assistant", "attempt", attempts)
|
logger.Info("Trying to reconnect to Home Assistant", "attempt", attempts)
|
||||||
|
|
||||||
err := Subscribe(logger)
|
err := Subscribe(logger, cfg)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,10 @@ func Close() {
|
||||||
client.Close()
|
client.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func JetstreamConnect(parentContext context.Context, parentLogger *slog.Logger) error {
|
func JetstreamConnect(parentContext context.Context, parentLogger *slog.Logger, parentConfig *config.HatsConfig) error {
|
||||||
ctx = parentContext
|
ctx = parentContext
|
||||||
logger = parentLogger
|
logger = parentLogger
|
||||||
cfg = config.FromEnvironment()
|
cfg = parentConfig
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
client = n.DefaultNatsConnection().WithHostName(cfg.NatsHost).WithPort(cfg.NatsPort).WithConnectionOption(nats.Name(cfg.NatsClientName))
|
client = n.DefaultNatsConnection().WithHostName(cfg.NatsHost).WithPort(cfg.NatsPort).WithConnectionOption(nats.Name(cfg.NatsClientName))
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.jhot.me/jhot/hats/pkg/config"
|
|
||||||
"code.jhot.me/jhot/hats/pkg/homeassistant"
|
"code.jhot.me/jhot/hats/pkg/homeassistant"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,7 +14,6 @@ var (
|
||||||
|
|
||||||
func initHomeAssistantClient() {
|
func initHomeAssistantClient() {
|
||||||
if haClient == nil {
|
if haClient == nil {
|
||||||
cfg = config.FromEnvironment()
|
|
||||||
haClient = homeassistant.NewRestClient(cfg.GetHomeAssistantBaseUrl(), cfg.HomeAssistantToken)
|
haClient = homeassistant.NewRestClient(cfg.GetHomeAssistantBaseUrl(), cfg.HomeAssistantToken)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
main.go
14
main.go
|
@ -26,15 +26,21 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cfg = config.FromEnvironment()
|
var err error
|
||||||
|
cfg, err = config.New()
|
||||||
ctx, cancel = context.WithCancel(context.Background())
|
ctx, cancel = context.WithCancel(context.Background())
|
||||||
logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
||||||
Level: cfg.GetLogLevel(),
|
Level: cfg.GetLogLevel(),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error during config initialization", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
interrupt = make(chan os.Signal, 1)
|
interrupt = make(chan os.Signal, 1)
|
||||||
signal.Notify(interrupt, os.Interrupt)
|
signal.Notify(interrupt, os.Interrupt)
|
||||||
|
|
||||||
err := nats.JetstreamConnect(ctx, logger)
|
err = nats.JetstreamConnect(ctx, logger, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -52,7 +58,7 @@ func main() {
|
||||||
nats.GetExistingSchedules()
|
nats.GetExistingSchedules()
|
||||||
defer nats.StopSchedules()
|
defer nats.StopSchedules()
|
||||||
|
|
||||||
err = homeassistant.Subscribe(logger)
|
err = homeassistant.Subscribe(logger, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -60,7 +66,7 @@ func main() {
|
||||||
|
|
||||||
ntfy.InitClient(cfg)
|
ntfy.InitClient(cfg)
|
||||||
|
|
||||||
api.Listen(logger, readme)
|
api.Listen(logger, cfg, readme)
|
||||||
defer api.Close()
|
defer api.Close()
|
||||||
|
|
||||||
for sig := range interrupt {
|
for sig := range interrupt {
|
||||||
|
|
|
@ -3,71 +3,168 @@ package config
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.jhot.me/jhot/hats/internal/util"
|
"code.jhot.me/jhot/hats/pkg/infisical"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HatsConfig struct {
|
type HatsConfig struct {
|
||||||
LogLevl string
|
LogLevl string `config:"LOG_LEVEL" default:"INFO"`
|
||||||
|
|
||||||
HomeAssistantHost string
|
InfisicalHost string `config:"INFISICAL_HOST" default:"http://infisical:8080"`
|
||||||
HomeAssistantPort string
|
InfisicalClientID string `config:"INFISICAL_CLIENT" default:""`
|
||||||
HomeAssistantSecure bool
|
InfisicalClientSecret string `config:"INFISICAL_SECRET" default:""`
|
||||||
HomeAssistantToken string
|
InfisicalProjectID string `config:"INFISICAL_PROJECT" default:""`
|
||||||
|
InfisicalEnvironment string `config:"INFISICAL_ENVIRONMENT" default:"prod"`
|
||||||
|
|
||||||
NatsHost string
|
HomeAssistantHost string `config:"HASS_HOST" default:"127.0.0.1"`
|
||||||
NatsPort string
|
HomeAssistantPort string `config:"HASS_PORT" default:"8123"`
|
||||||
NatsToken string
|
HomeAssistantSecure bool `config:"HASS_SECURE" default:"false"`
|
||||||
NatsClientName string
|
HomeAssistantToken string `config:"HASS_TOKEN" default:""`
|
||||||
|
|
||||||
HatsHost string
|
NatsHost string `config:"NATS_HOST" default:"127.0.0.1"`
|
||||||
HatsPort string
|
NatsPort string `config:"NATS_PORT" default:"4222"`
|
||||||
HatsToken string
|
NatsToken string `config:"NATS_TOKEN" default:""`
|
||||||
HatsSecure bool
|
NatsClientName string `config:"NATS_CLIENT_NAME" default:"hats"`
|
||||||
|
|
||||||
NtfyHost string
|
HatsHost string `config:"HATS_HOST" default:"hats"`
|
||||||
NtfyToken string
|
HatsPort string `config:"HATS_PORT" default:"8888"`
|
||||||
|
HatsToken string `config:"HATS_TOKEN" default:""`
|
||||||
|
HatsSecure bool `config:"HATS_SECURE" default:"false"`
|
||||||
|
|
||||||
ConfigDir string
|
NtfyHost string `config:"NTFY_HOST" default:"https://ntfy.sh"`
|
||||||
|
NtfyToken string `config:"NTFY_TOKEN" default:""`
|
||||||
|
|
||||||
|
SyncthingHost string `config:"SYNCTHING_HOST" default:"http://127.0.0.1:8384"`
|
||||||
|
SyncthingToken string `config:"SYNCTHING_TOKEN" default:""`
|
||||||
|
|
||||||
|
GokapiHost string `config:"GOKAPI_HOST" default:"http://gokapi:53842"`
|
||||||
|
GokapiToken string `config:"GOKAPI_TOKEN" default:""`
|
||||||
|
|
||||||
|
QbittorrentHost string `config:"QBITTORRENT_HOST" default:"http://qbittorrent:8080"`
|
||||||
|
QbittorrentUser string `config:"QBITTORRENT_USER" default:""`
|
||||||
|
QbittorrentPassword string `config:"QBITTORRENT_PASS" default:""`
|
||||||
|
|
||||||
|
ConfigDir string `config:"CONFIG_DIR" default:"/config"`
|
||||||
|
|
||||||
|
infisicalClient *infisical.InfisicalClient
|
||||||
|
infisicalRetrievalOpts *infisical.RetrieveSecretOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromEnvironment() *HatsConfig {
|
func New() (*HatsConfig, error) {
|
||||||
config := &HatsConfig{
|
cfg := &HatsConfig{}
|
||||||
LogLevl: util.GetEnvWithDefault("LOG_LEVEL", "INFO"),
|
cfg.SetValues(ConfigValueSourceDefault).SetValues(ConfigValueSourceEnv)
|
||||||
|
|
||||||
HomeAssistantHost: util.GetEnvWithDefault("HASS_HOST", "127.0.0.1"),
|
if cfg.InfisicalConfigured() {
|
||||||
HomeAssistantPort: util.GetEnvWithDefault("HASS_PORT", "8123"),
|
cfg.infisicalClient = infisical.New(cfg.InfisicalHost, cfg.InfisicalClientID, cfg.InfisicalClientSecret)
|
||||||
HomeAssistantToken: util.GetEnvWithDefault("HASS_TOKEN", ""),
|
|
||||||
|
|
||||||
NatsHost: util.GetEnvWithDefault("NATS_HOST", "127.0.0.1"),
|
err := cfg.infisicalClient.Login()
|
||||||
NatsPort: util.GetEnvWithDefault("NATS_PORT", "4222"),
|
if err != nil {
|
||||||
NatsToken: util.GetEnvWithDefault("NATS_TOKEN", ""),
|
cfg.infisicalClient = nil
|
||||||
NatsClientName: util.GetEnvWithDefault("NATS_CLIENT_NAME", "hats"),
|
return cfg, fmt.Errorf("error logging in to Infisical: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
HatsHost: util.GetEnvWithDefault("HATS_HOST", "hats"),
|
cfg.infisicalRetrievalOpts = &infisical.RetrieveSecretOptions{
|
||||||
HatsPort: util.GetEnvWithDefault("HATS_PORT", "8888"),
|
WorkspaceID: cfg.InfisicalProjectID,
|
||||||
HatsToken: util.GetEnvWithDefault("HATS_TOKEN", ""),
|
Environment: cfg.InfisicalEnvironment,
|
||||||
|
SecretPath: "/",
|
||||||
|
IncludeImports: false,
|
||||||
|
}
|
||||||
|
|
||||||
NtfyHost: util.GetEnvWithDefault("NTFY_HOST", "https://ntfy.sh"),
|
secrets, err := cfg.infisicalClient.ListSecrets(cfg.infisicalRetrievalOpts)
|
||||||
NtfyToken: util.GetEnvWithDefault("NTFY_TOKEN", ""),
|
if err != nil {
|
||||||
|
return cfg, fmt.Errorf("error getting Infisical secrets: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
ConfigDir: util.GetEnvWithDefault("CONFIG_DIR", "/config"),
|
secretsMap := make(map[string]string)
|
||||||
|
for _, secret := range secrets {
|
||||||
|
secretsMap[secret.SecretKey] = secret.SecretValue
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.SetValues(ConfigValueSourceInfisical, secretsMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
config.HomeAssistantSecure, _ = strconv.ParseBool(util.GetEnvWithDefault("HASS_SECURE", "false"))
|
return cfg, nil
|
||||||
config.HatsSecure, _ = strconv.ParseBool(util.GetEnvWithDefault("HATS_SECURE", "false"))
|
}
|
||||||
|
|
||||||
return config
|
type ConfigValueSource string
|
||||||
|
|
||||||
|
const ConfigValueSourceEnv ConfigValueSource = "env"
|
||||||
|
const ConfigValueSourceDefault ConfigValueSource = "default"
|
||||||
|
const ConfigValueSourceInfisical ConfigValueSource = "infisical"
|
||||||
|
|
||||||
|
func (c *HatsConfig) SetValues(source ConfigValueSource, inputs ...map[string]string) *HatsConfig {
|
||||||
|
fields := reflect.VisibleFields(reflect.TypeOf(*c))
|
||||||
|
|
||||||
|
for _, field := range fields {
|
||||||
|
envName := field.Tag.Get("config")
|
||||||
|
if envName == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var envValue string
|
||||||
|
switch source {
|
||||||
|
case ConfigValueSourceDefault:
|
||||||
|
envValue = field.Tag.Get("default")
|
||||||
|
case ConfigValueSourceEnv:
|
||||||
|
envValue = os.Getenv(envName)
|
||||||
|
case ConfigValueSourceInfisical:
|
||||||
|
if len(inputs) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if val, found := inputs[0][envName]; found {
|
||||||
|
envValue = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if envValue == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
f := reflect.ValueOf(c).Elem().FieldByName(field.Name)
|
||||||
|
switch field.Type.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
f.SetBool(strings.EqualFold(envValue, "true"))
|
||||||
|
case reflect.Int:
|
||||||
|
parsed, err := strconv.ParseInt(envValue, 10, 64)
|
||||||
|
if err == nil {
|
||||||
|
f.SetInt(parsed)
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
f.SetString(envValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *HatsConfig) GetCustomSetting(name string, defaultValue string) string {
|
||||||
|
returnValue := defaultValue
|
||||||
|
|
||||||
|
envValue := os.Getenv(name)
|
||||||
|
if envValue != "" {
|
||||||
|
returnValue = envValue
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.InfisicalConfigured() {
|
||||||
|
secret, _ := c.infisicalClient.GetSecret(name, c.infisicalRetrievalOpts)
|
||||||
|
if secret.SecretValue != "" {
|
||||||
|
returnValue = secret.SecretValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HatsConfig) GetHomeAssistantBaseUrl() string {
|
func (c *HatsConfig) GetHomeAssistantBaseUrl() string {
|
||||||
hassProtocol := "http"
|
protocol := "http"
|
||||||
if c.HomeAssistantSecure {
|
if c.HomeAssistantSecure {
|
||||||
hassProtocol += "s"
|
protocol += "s"
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s://%s:%s", hassProtocol, c.HomeAssistantHost, c.HomeAssistantPort)
|
return fmt.Sprintf("%s://%s:%s", protocol, c.HomeAssistantHost, c.HomeAssistantPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HatsConfig) GetHomeAssistantWebsocketUrl() string {
|
func (c *HatsConfig) GetHomeAssistantWebsocketUrl() string {
|
||||||
|
@ -102,3 +199,11 @@ func (c *HatsConfig) GetLogLevel() slog.Level {
|
||||||
return slog.LevelInfo
|
return slog.LevelInfo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *HatsConfig) InfisicalConfigured() bool {
|
||||||
|
return c.InfisicalHost != "" &&
|
||||||
|
c.InfisicalClientID != "" &&
|
||||||
|
c.InfisicalClientSecret != "" &&
|
||||||
|
c.InfisicalProjectID != "" &&
|
||||||
|
c.InfisicalEnvironment != ""
|
||||||
|
}
|
||||||
|
|
|
@ -27,10 +27,6 @@ func New(host string, token string) *GokapiClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFromEnv() *GokapiClient {
|
|
||||||
return New(os.Getenv("GOKAPI_HOST"), os.Getenv("GOKAPI_TOKEN"))
|
|
||||||
}
|
|
||||||
|
|
||||||
type GokapiFile struct {
|
type GokapiFile struct {
|
||||||
ID string `json:"Id"`
|
ID string `json:"Id"`
|
||||||
Name string `json:"Name"`
|
Name string `json:"Name"`
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
package infisical
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.jhot.me/jhot/hats/internal/util"
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InfisicalClient struct {
|
||||||
|
restClient *resty.Client
|
||||||
|
host string
|
||||||
|
clientId string
|
||||||
|
clientSecret string
|
||||||
|
accessToken string
|
||||||
|
tokenExpiration time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(host string, clientId string, clientSecret string) *InfisicalClient {
|
||||||
|
return &InfisicalClient{
|
||||||
|
restClient: resty.New().SetBaseURL(fmt.Sprintf("%s/api", host)),
|
||||||
|
host: host,
|
||||||
|
clientId: clientId,
|
||||||
|
clientSecret: clientSecret,
|
||||||
|
accessToken: "",
|
||||||
|
tokenExpiration: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InfisicalClient) Login() error {
|
||||||
|
var result LoginResponse
|
||||||
|
_, err := util.CheckSuccess(c.restClient.R().SetFormData(map[string]string{
|
||||||
|
"clientId": c.clientId,
|
||||||
|
"clientSecret": c.clientSecret,
|
||||||
|
}).SetResult(&result).Post("v1/auth/universal-auth/login"))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.restClient.SetAuthScheme(result.TokenType).SetAuthToken(result.AccessToken)
|
||||||
|
c.accessToken = result.AccessToken
|
||||||
|
c.tokenExpiration = time.Now().Add(time.Duration(result.ExpiresIn) * time.Second)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InfisicalClient) CheckToken() error {
|
||||||
|
if c.accessToken == "" {
|
||||||
|
return fmt.Errorf("access token empty, please login first")
|
||||||
|
}
|
||||||
|
|
||||||
|
if time.Now().Before(c.tokenExpiration) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var result LoginResponse
|
||||||
|
_, err := util.CheckSuccess(c.restClient.R().SetResult(&result).SetBody(map[string]interface{}{
|
||||||
|
"accessToken": c.accessToken,
|
||||||
|
}).Post("v1/auth/token/renew"))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error renewing token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.restClient.SetAuthScheme(result.TokenType).SetAuthToken(result.AccessToken)
|
||||||
|
c.accessToken = result.AccessToken
|
||||||
|
c.tokenExpiration = time.Now().Add(time.Duration(result.ExpiresIn) * time.Second)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InfisicalClient) ListSecrets(opts *RetrieveSecretOptions) ([]Secret, error) {
|
||||||
|
err := c.CheckToken()
|
||||||
|
if err != nil {
|
||||||
|
return []Secret{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result SecretsResponse
|
||||||
|
_, err = util.CheckSuccess(c.restClient.R().SetResult(&result).SetQueryParams(map[string]string{
|
||||||
|
"workspaceId": opts.WorkspaceID,
|
||||||
|
"environment": opts.Environment,
|
||||||
|
"secretPath": opts.SecretPath,
|
||||||
|
"include_imports": fmt.Sprintf("%t", opts.IncludeImports),
|
||||||
|
}).Get("v3/secrets/raw"))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return []Secret{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.Secrets, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InfisicalClient) GetSecret(name string, opts *RetrieveSecretOptions) (Secret, error) {
|
||||||
|
err := c.CheckToken()
|
||||||
|
if err != nil {
|
||||||
|
return Secret{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result SecretResponse
|
||||||
|
_, err = util.CheckSuccess(c.restClient.R().SetResult(&result).SetQueryParams(map[string]string{
|
||||||
|
"workspaceId": opts.WorkspaceID,
|
||||||
|
"environment": opts.Environment,
|
||||||
|
"secretPath": opts.SecretPath,
|
||||||
|
"include_imports": fmt.Sprintf("%t", opts.IncludeImports),
|
||||||
|
"type": "shared",
|
||||||
|
}).Get("v3/secrets/raw/" + name))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return Secret{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.Secret, nil
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package infisical
|
||||||
|
|
||||||
|
type LoginResponse struct {
|
||||||
|
AccessToken string `json:"accessToken"`
|
||||||
|
ExpiresIn int `json:"expiresIn"`
|
||||||
|
AccessTokenMaxTTL int `json:"accessTokenMaxTTL"`
|
||||||
|
TokenType string `json:"tokenType"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RetrieveSecretOptions struct {
|
||||||
|
WorkspaceID string
|
||||||
|
Environment string
|
||||||
|
SecretPath string
|
||||||
|
IncludeImports bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultRetrieveSecretOptions() *RetrieveSecretOptions {
|
||||||
|
return &RetrieveSecretOptions{
|
||||||
|
WorkspaceID: "",
|
||||||
|
Environment: "",
|
||||||
|
SecretPath: "/",
|
||||||
|
IncludeImports: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *RetrieveSecretOptions) WithWorkspaceID(workspaceId string) *RetrieveSecretOptions {
|
||||||
|
o.WorkspaceID = workspaceId
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *RetrieveSecretOptions) WithEnvironment(environment string) *RetrieveSecretOptions {
|
||||||
|
o.Environment = environment
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *RetrieveSecretOptions) WithSecretPath(secretPath string) *RetrieveSecretOptions {
|
||||||
|
o.SecretPath = secretPath
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *RetrieveSecretOptions) WithImports(includeImports bool) *RetrieveSecretOptions {
|
||||||
|
o.IncludeImports = includeImports
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
type Secret struct {
|
||||||
|
ID string `json:"_id"`
|
||||||
|
Environment string `json:"environment,omitempty"`
|
||||||
|
SecretComment string `json:"secretComment,omitempty"`
|
||||||
|
SecretKey string `json:"secretKey,omitempty"`
|
||||||
|
SecretValue string `json:"secretValue,omitempty"`
|
||||||
|
Version int `json:"version,omitempty"`
|
||||||
|
Workspace string `json:"workspace,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecretsResponse struct {
|
||||||
|
Secrets []Secret `json:"secrets"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecretResponse struct {
|
||||||
|
Secret Secret `json:"secret"`
|
||||||
|
}
|
|
@ -3,7 +3,6 @@ package qbittorrent
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -21,12 +20,6 @@ func New(host string) *QbittorrentClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFromEnv() (*QbittorrentClient, error) {
|
|
||||||
c := New(os.Getenv("QBITTORRENT_HOST"))
|
|
||||||
err := c.Login(os.Getenv("QBITTORRENT_USER"), os.Getenv("QBITTORRENT_PASS"))
|
|
||||||
return c, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *QbittorrentClient) Login(user string, pass string) error {
|
func (c *QbittorrentClient) Login(user string, pass string) error {
|
||||||
resp, err := util.CheckSuccess(c.restClient.R().SetFormData(map[string]string{
|
resp, err := util.CheckSuccess(c.restClient.R().SetFormData(map[string]string{
|
||||||
"username": user,
|
"username": user,
|
||||||
|
|
|
@ -2,7 +2,6 @@ package syncthing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
|
|
||||||
"code.jhot.me/jhot/hats/internal/util"
|
"code.jhot.me/jhot/hats/internal/util"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
|
@ -20,10 +19,6 @@ func New(host string, token string) *SyncthingClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFromEnv() *SyncthingClient {
|
|
||||||
return New(os.Getenv("SYNCTHING_HOST"), os.Getenv("SYNCTHING_TOKEN"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SyncthingClient) GetVersion() (VersionInfo, error) {
|
func (c *SyncthingClient) GetVersion() (VersionInfo, error) {
|
||||||
var data VersionInfo
|
var data VersionInfo
|
||||||
_, err := util.CheckSuccess(c.restClient.R().SetResult(&data).Get("system/version"))
|
_, err := util.CheckSuccess(c.restClient.R().SetResult(&data).Get("system/version"))
|
||||||
|
|
Loading…
Reference in New Issue