diff --git a/.golangci.yml b/.golangci.yml index 8c2d951..2b4c948 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,88 +1,48 @@ -version: "2" +run: + timeout: 5m + modules-download-mode: readonly + +linters-settings: + gofmt: + simplify: true + goimports: + local-prefixes: github.com/mattermost/mattermost-plugin-bridge-xmpp + govet: + check-shadowing: true + enable-all: true + disable: + - fieldalignment + misspell: + locale: US linters: + disable-all: true enable: - bodyclose - errcheck - gocritic + - gofmt + - goimports - gosec + - gosimple + - govet - ineffassign - misspell - nakedret - revive - - staticcheck # Now includes gosimple and stylecheck + - staticcheck + - stylecheck - typecheck - unconvert - unused - whitespace - - govet # Ensure this is included - - settings: - errcheck: - # Add any errcheck settings here - exclude-functions: - - io.Copy(*bytes.Buffer) - - gocritic: - enabled-tags: - - diagnostic - - experimental - - opinionated - - performance - - style - - gosec: - # Add gosec settings - excludes: - - G104 # Errors unhandled - - staticcheck: - # Configure staticcheck (includes gosimple/stylecheck checks) - checks: ["all"] - - revive: - # Add revive rules - rules: - - name: exported - disabled: false - - exclusions: - presets: - - comments - - std-error-handling - - common-false-positives - - rules: - - path: '_test\.go' - linters: - - errcheck - - gosec - -formatters: - enable: - - gofmt - - goimports - - settings: - gofmt: - simplify: true - - goimports: - local-prefixes: - - github.com/mattermost/mattermost-plugin-bridge-xmpp - -output: - formats: - text: - path: stdout - colors: true - print-linter-name: true - -run: - timeout: 5m - tests: true issues: - max-issues-per-linter: 0 - max-same-issues: 0 - fix: false + exclude-rules: + - path: server/configuration.go + linters: + - unused + - path: _test\.go + linters: + - bodyclose + - scopelint # https://github.com/kyoh86/scopelint/issues/4 diff --git a/build/test.mk b/build/test.mk index 16261da..e7691a2 100644 --- a/build/test.mk +++ b/build/test.mk @@ -2,13 +2,11 @@ # Testing and Quality Assurance # ==================================================================================== -GOLANGCI_LINT_BINARY = ./build/bin/golangci-lint -GOTESTSUM_BINARY = ./build/bin/gotestsum - ## Install go tools install-go-tools: - @echo "Installing development tools..." - @pluginctl tools install --bin-dir ./build/bin + @echo Installing go tools + $(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.61.0 + $(GO) install gotest.tools/gotestsum@v1.7.0 ## Runs eslint and golangci-lint .PHONY: check-style @@ -26,14 +24,14 @@ endif ifneq ($(HAS_SERVER),) @echo Running golangci-lint $(GO) vet ./... - $(GOLANGCI_LINT_BINARY) run ./... + $(GOBIN)/golangci-lint run ./... endif ## Runs any lints and unit tests defined for the server and webapp, if they exist. .PHONY: test test: apply webapp/node_modules install-go-tools ifneq ($(HAS_SERVER),) - $(GOTESTSUM_BINARY) -- -v ./... + $(GOBIN)/gotestsum -- -v ./... endif ifneq ($(HAS_WEBAPP),) cd webapp && $(NPM) run test; @@ -44,7 +42,7 @@ endif .PHONY: test-ci test-ci: apply webapp/node_modules install-go-tools ifneq ($(HAS_SERVER),) - $(GOTESTSUM_BINARY) --format standard-verbose --junitfile report.xml -- ./... + $(GOBIN)/gotestsum --format standard-verbose --junitfile report.xml -- ./... endif ifneq ($(HAS_WEBAPP),) cd webapp && $(NPM) run test; diff --git a/cmd/xmpp-client-doctor/main.go b/cmd/xmpp-client-doctor/main.go index ac179e8..020e5da 100644 --- a/cmd/xmpp-client-doctor/main.go +++ b/cmd/xmpp-client-doctor/main.go @@ -27,8 +27,6 @@ type Config struct { Resource string TestRoom string TestMUC bool - TestDirectMessage bool - TestRoomExists bool Verbose bool InsecureSkipVerify bool } @@ -43,23 +41,20 @@ func main() { flag.StringVar(&config.Resource, "resource", defaultResource, "XMPP resource") flag.StringVar(&config.TestRoom, "test-room", defaultTestRoom, "MUC room JID for testing") flag.BoolVar(&config.TestMUC, "test-muc", true, "Enable MUC room testing (join/wait/leave)") - flag.BoolVar(&config.TestDirectMessage, "test-dm", true, "Enable direct message testing (send message to admin user)") - flag.BoolVar(&config.TestRoomExists, "test-room-exists", true, "Enable room existence testing using disco#info") flag.BoolVar(&config.Verbose, "verbose", true, "Enable verbose logging") flag.BoolVar(&config.InsecureSkipVerify, "insecure-skip-verify", true, "Skip TLS certificate verification (for development)") flag.Usage = func() { fmt.Fprintf(os.Stderr, "xmpp-client-doctor - Test XMPP client connectivity and MUC operations\n\n") fmt.Fprintf(os.Stderr, "This tool tests the XMPP client implementation by connecting to an XMPP server,\n") - fmt.Fprintf(os.Stderr, "performing connection tests, room existence checks, optionally testing MUC room operations\n") - fmt.Fprintf(os.Stderr, "and direct messages, and then disconnecting gracefully.\n\n") + fmt.Fprintf(os.Stderr, "performing connection tests, optionally testing MUC room operations,\n") + fmt.Fprintf(os.Stderr, "and then disconnecting gracefully.\n\n") fmt.Fprintf(os.Stderr, "Usage:\n") fmt.Fprintf(os.Stderr, " %s [flags]\n\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Examples:\n") fmt.Fprintf(os.Stderr, " %s # Test basic connectivity\n", os.Args[0]) fmt.Fprintf(os.Stderr, " %s --test-muc # Test connectivity and MUC operations\n", os.Args[0]) - fmt.Fprintf(os.Stderr, " %s --test-dm # Test connectivity and direct messages\n", os.Args[0]) - fmt.Fprintf(os.Stderr, " %s --test-muc=false --test-dm=false # Test connectivity only\n\n", os.Args[0]) + fmt.Fprintf(os.Stderr, " %s --test-muc=false # Test connectivity only\n\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Flags:\n") flag.PrintDefaults() fmt.Fprintf(os.Stderr, "\nDefault values are configured for the development server in ./sidecar/\n") @@ -80,12 +75,6 @@ func main() { if config.TestMUC { log.Printf(" Test Room: %s", config.TestRoom) } - if config.TestDirectMessage { - log.Printf(" Test Direct Messages: enabled") - } - if config.TestRoomExists { - log.Printf(" Test Room Existence: enabled") - } } // Test the XMPP client @@ -100,12 +89,6 @@ func main() { if config.TestMUC { fmt.Println("✅ XMPP MUC operations test passed!") } - if config.TestDirectMessage { - fmt.Println("✅ XMPP direct message test passed!") - } - if config.TestRoomExists { - fmt.Println("✅ XMPP room existence test passed!") - } } } @@ -114,9 +97,6 @@ func testXMPPClient(config *Config) error { log.Printf("Creating XMPP client...") } - // Create a simple logger for the XMPP client - doctorLogger := &SimpleLogger{verbose: config.Verbose} - // Create XMPP client with optional TLS configuration var client *xmpp.Client if config.InsecureSkipVerify { @@ -133,7 +113,6 @@ func testXMPPClient(config *Config) error { config.Resource, "doctor-remote-id", tlsConfig, - doctorLogger, ) } else { client = xmpp.NewClient( @@ -142,7 +121,6 @@ func testXMPPClient(config *Config) error { config.Password, config.Resource, "doctor-remote-id", - doctorLogger, ) } @@ -165,7 +143,7 @@ func testXMPPClient(config *Config) error { // Test connection health start = time.Now() - err = client.Ping() + err = client.TestConnection() if err != nil { return fmt.Errorf("connection health test failed: %w", err) } @@ -176,9 +154,7 @@ func testXMPPClient(config *Config) error { } var mucDuration time.Duration - var dmDuration time.Duration - var roomExistsDuration time.Duration - + // Test MUC operations if requested if config.TestMUC { start = time.Now() @@ -189,26 +165,6 @@ func testXMPPClient(config *Config) error { mucDuration = time.Since(start) } - // Test direct message if requested - if config.TestDirectMessage { - start = time.Now() - err = testDirectMessage(client, config) - if err != nil { - return fmt.Errorf("direct message test failed: %w", err) - } - dmDuration = time.Since(start) - } - - // Test room existence if requested - if config.TestRoomExists { - start = time.Now() - err = testRoomExists(client, config) - if err != nil { - return fmt.Errorf("room existence test failed: %w", err) - } - roomExistsDuration = time.Since(start) - } - if config.Verbose { log.Printf("Disconnecting from XMPP server...") } @@ -229,23 +185,11 @@ func testXMPPClient(config *Config) error { if config.TestMUC { log.Printf(" MUC operations time: %v", mucDuration) } - if config.TestDirectMessage { - log.Printf(" Direct message time: %v", dmDuration) - } - if config.TestRoomExists { - log.Printf(" Room existence check time: %v", roomExistsDuration) - } log.Printf(" Disconnect time: %v", disconnectDuration) totalTime := connectDuration + pingDuration + disconnectDuration if config.TestMUC { totalTime += mucDuration } - if config.TestDirectMessage { - totalTime += dmDuration - } - if config.TestRoomExists { - totalTime += roomExistsDuration - } log.Printf(" Total time: %v", totalTime) } @@ -255,38 +199,17 @@ func testXMPPClient(config *Config) error { func testMUCOperations(client *xmpp.Client, config *Config) error { if config.Verbose { log.Printf("Testing MUC operations with room: %s", config.TestRoom) - log.Printf("First checking if room exists...") - } - - // Check if room exists before attempting to join - start := time.Now() - exists, err := client.CheckRoomExists(config.TestRoom) - if err != nil { - return fmt.Errorf("failed to check room existence for %s: %w", config.TestRoom, err) - } - checkDuration := time.Since(start) - - if config.Verbose { - log.Printf("✅ Room existence check completed in %v", checkDuration) - log.Printf("Room %s exists: %t", config.TestRoom, exists) - } - - if !exists { - return fmt.Errorf("cannot test MUC operations: room %s does not exist or is not accessible", config.TestRoom) - } - - if config.Verbose { - log.Printf("Room exists, proceeding to join...") + log.Printf("Attempting to join MUC room...") } // Test joining the room - start = time.Now() - err = client.JoinRoom(config.TestRoom) + start := time.Now() + err := client.JoinRoom(config.TestRoom) if err != nil { return fmt.Errorf("failed to join MUC room %s: %w", config.TestRoom, err) } joinDuration := time.Since(start) - + var sendDuration time.Duration if config.Verbose { @@ -300,7 +223,7 @@ func testMUCOperations(client *xmpp.Client, config *Config) error { RoomJID: config.TestRoom, Message: testMessage, } - + start = time.Now() _, err = client.SendMessage(messageReq) if err != nil { @@ -332,84 +255,11 @@ func testMUCOperations(client *xmpp.Client, config *Config) error { if config.Verbose { log.Printf("✅ Successfully left MUC room in %v", leaveDuration) log.Printf("MUC operations summary:") - log.Printf(" Room existence check time: %v", checkDuration) log.Printf(" Join time: %v", joinDuration) log.Printf(" Send message time: %v", sendDuration) log.Printf(" Wait time: 5s") log.Printf(" Leave time: %v", leaveDuration) - log.Printf(" Total MUC time: %v", checkDuration+joinDuration+sendDuration+5*time.Second+leaveDuration) - } - - return nil -} - -func testDirectMessage(client *xmpp.Client, config *Config) error { - if config.Verbose { - log.Printf("Testing direct message functionality...") - log.Printf("Sending test message to admin user...") - } - - // Send a test message to the admin user - testMessage := fmt.Sprintf("Test direct message from XMPP doctor at %s", time.Now().Format("15:04:05")) - adminJID := "admin@localhost" // Default admin user for development server - - start := time.Now() - err := client.SendDirectMessage(adminJID, testMessage) - if err != nil { - return fmt.Errorf("failed to send direct message to %s: %w", adminJID, err) - } - sendDuration := time.Since(start) - - if config.Verbose { - log.Printf("✅ Successfully sent direct message in %v", sendDuration) - log.Printf("Message: %s", testMessage) - log.Printf("Recipient: %s", adminJID) - log.Printf("Direct message test summary:") - log.Printf(" Send message time: %v", sendDuration) - } - - return nil -} - -func testRoomExists(client *xmpp.Client, config *Config) error { - if config.Verbose { - log.Printf("Testing room existence functionality...") - log.Printf("Checking if test room exists: %s", config.TestRoom) - } - - // Test room existence check - start := time.Now() - exists, err := client.CheckRoomExists(config.TestRoom) - if err != nil { - return fmt.Errorf("failed to check room existence for %s: %w", config.TestRoom, err) - } - checkDuration := time.Since(start) - - if config.Verbose { - log.Printf("✅ Room existence check completed in %v", checkDuration) - log.Printf("Room %s exists: %t", config.TestRoom, exists) - } - - // Test with a non-existent room to verify negative case - nonExistentRoom := "nonexistent-room-12345@conference.localhost" - if config.Verbose { - log.Printf("Testing negative case with non-existent room: %s", nonExistentRoom) - } - - start = time.Now() - existsNegative, err := client.CheckRoomExists(nonExistentRoom) - if err != nil { - return fmt.Errorf("failed to check non-existent room %s: %w", nonExistentRoom, err) - } - checkNegativeDuration := time.Since(start) - - if config.Verbose { - log.Printf("✅ Negative room existence check completed in %v", checkNegativeDuration) - log.Printf("Non-existent room %s exists: %t (should be false)", nonExistentRoom, existsNegative) - log.Printf("Room existence test summary:") - log.Printf(" Test room check time: %v", checkDuration) - log.Printf(" Negative case check time: %v", checkNegativeDuration) - log.Printf(" Total room existence test time: %v", checkDuration+checkNegativeDuration) + log.Printf(" Total MUC time: %v", joinDuration+sendDuration+5*time.Second+leaveDuration) } return nil @@ -420,31 +270,4 @@ func maskPassword(password string) string { return "****" } return password[:2] + "****" -} - -// SimpleLogger provides basic logging functionality for the doctor command -type SimpleLogger struct { - verbose bool -} - -// LogDebug logs debug messages if verbose mode is enabled -func (l *SimpleLogger) LogDebug(msg string, args ...interface{}) { - if l.verbose { - log.Printf("[DEBUG] "+msg, args...) - } -} - -// LogInfo logs info messages -func (l *SimpleLogger) LogInfo(msg string, args ...interface{}) { - log.Printf("[INFO] "+msg, args...) -} - -// LogWarn logs warning messages -func (l *SimpleLogger) LogWarn(msg string, args ...interface{}) { - log.Printf("[WARN] "+msg, args...) -} - -// LogError logs error messages -func (l *SimpleLogger) LogError(msg string, args ...interface{}) { - log.Printf("[ERROR] "+msg, args...) -} +} \ No newline at end of file diff --git a/go.mod b/go.mod index efd6373..0dd6bd5 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/mattermost/mattermost-plugin-bridge-xmpp go 1.24.3 require ( + github.com/golang/mock v1.6.0 github.com/gorilla/mux v1.8.1 github.com/mattermost/mattermost/server/public v0.1.10 github.com/pkg/errors v0.9.1 @@ -12,225 +13,53 @@ require ( ) require ( - 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect - 4d63.com/gochecknoglobals v0.2.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect - github.com/4meepo/tagalign v1.3.4 // indirect - github.com/Abirdcfly/dupword v0.1.1 // indirect - github.com/Antonboom/errname v0.1.13 // indirect - github.com/Antonboom/nilnil v0.1.9 // indirect - github.com/Antonboom/testifylint v1.4.3 // indirect - github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect - github.com/Crocmagnon/fatcontext v0.5.2 // indirect - github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect - github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect - github.com/Masterminds/semver/v3 v3.3.0 // indirect - github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect - github.com/alecthomas/go-check-sumtype v0.1.4 // indirect - github.com/alexkohler/nakedret/v2 v2.0.4 // indirect - github.com/alexkohler/prealloc v1.0.0 // indirect - github.com/alingse/asasalint v0.0.11 // indirect - github.com/ashanbrown/forbidigo v1.6.0 // indirect - github.com/ashanbrown/makezero v1.1.1 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/bkielbasa/cyclop v1.2.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/blizzy78/varnamelen v0.8.0 // indirect - github.com/bombsimon/wsl/v4 v4.4.1 // indirect - github.com/breml/bidichk v0.2.7 // indirect - github.com/breml/errchkjson v0.3.6 // indirect - github.com/butuzov/ireturn v0.3.0 // indirect - github.com/butuzov/mirror v1.2.0 // indirect - github.com/catenacyber/perfsprint v0.7.1 // indirect - github.com/ccojocar/zxcvbn-go v1.0.2 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/charithe/durationcheck v0.0.10 // indirect - github.com/chavacava/garif v0.1.0 // indirect - github.com/ckaznocha/intrange v0.2.0 // indirect - github.com/curioswitch/go-reassign v0.2.0 // indirect - github.com/daixiang0/gci v0.13.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/denis-tingaikin/go-header v0.5.0 // indirect - github.com/dnephin/pflag v1.0.7 // indirect github.com/dyatlov/go-opengraph/opengraph v0.0.0-20220524092352-606d7b1e5f8a // indirect - github.com/ettle/strcase v0.2.0 // indirect github.com/fatih/color v1.18.0 // indirect - github.com/fatih/structtag v1.2.0 // indirect - github.com/firefart/nonamedreturns v1.0.5 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/fzipp/gocyclo v0.6.0 // indirect - github.com/ghostiam/protogetter v0.3.6 // indirect github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect - github.com/go-critic/go-critic v0.11.4 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect - github.com/go-toolsmith/astcast v1.1.0 // indirect - github.com/go-toolsmith/astcopy v1.1.0 // indirect - github.com/go-toolsmith/astequal v1.2.0 // indirect - github.com/go-toolsmith/astfmt v1.1.0 // indirect - github.com/go-toolsmith/astp v1.1.0 // indirect - github.com/go-toolsmith/strparse v1.1.0 // indirect - github.com/go-toolsmith/typep v1.1.0 // indirect - github.com/go-viper/mapstructure/v2 v2.1.0 // indirect - github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect - github.com/gobwas/glob v0.2.3 // indirect - github.com/gofrs/flock v0.12.1 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect - github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 // indirect - github.com/golangci/golangci-lint v1.61.0 // indirect - github.com/golangci/misspell v0.6.0 // indirect - github.com/golangci/modinfo v0.3.4 // indirect - github.com/golangci/plugin-module-register v0.1.1 // indirect - github.com/golangci/revgrep v0.5.3 // indirect - github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gordonklaus/ineffassign v0.1.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/gostaticanalysis/analysisutil v0.7.1 // indirect - github.com/gostaticanalysis/comment v1.4.2 // indirect - github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect - github.com/gostaticanalysis/nilerr v0.1.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.6.3 // indirect - github.com/hashicorp/go-version v1.7.0 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.1.2 // indirect - github.com/hexops/gotextdiff v1.0.3 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jgautheron/goconst v1.7.1 // indirect - github.com/jingyugao/rowserrcheck v1.1.1 // indirect - github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect - github.com/jjti/go-spancheck v0.6.2 // indirect - github.com/jonboulle/clockwork v0.2.2 // indirect - github.com/julz/importas v0.1.0 // indirect - github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect - github.com/kisielk/errcheck v1.7.0 // indirect - github.com/kkHAIKE/contextcheck v1.1.5 // indirect - github.com/kulti/thelper v0.6.3 // indirect - github.com/kunwardeep/paralleltest v1.0.10 // indirect - github.com/kyoh86/exportloopref v0.1.11 // indirect - github.com/lasiar/canonicalheader v1.1.1 // indirect - github.com/ldez/gomoddirectives v0.2.4 // indirect - github.com/ldez/tagliatelle v0.5.0 // indirect - github.com/leonklingele/grouper v1.1.2 // indirect github.com/lib/pq v1.10.9 // indirect - github.com/lufeee/execinquery v1.2.1 // indirect - github.com/macabu/inamedparam v0.1.3 // indirect - github.com/magiconair/properties v1.8.6 // indirect - github.com/maratori/testableexamples v1.0.0 // indirect - github.com/maratori/testpackage v1.1.1 // indirect - github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 // indirect github.com/mattermost/ldap v0.0.0-20231116144001-0f480c025956 // indirect github.com/mattermost/logr/v2 v2.0.21 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.9 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/mgechev/revive v1.3.9 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moricho/tparallel v0.3.2 // indirect - github.com/nakabonne/nestif v0.3.1 // indirect - github.com/nishanths/exhaustive v0.12.0 // indirect - github.com/nishanths/predeclared v0.2.2 // indirect - github.com/nunnatsa/ginkgolinter v0.16.2 // indirect github.com/oklog/run v1.1.0 // indirect - github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pborman/uuid v1.2.1 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/polyfloyd/go-errorlint v1.6.0 // indirect - github.com/prometheus/client_golang v1.12.1 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.32.1 // indirect - github.com/prometheus/procfs v0.7.3 // indirect - github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 // indirect - github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect - github.com/quasilyte/gogrep v0.5.0 // indirect - github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect - github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect - github.com/ryancurrah/gomodguard v1.3.5 // indirect - github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect - github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect - github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect - github.com/sashamelentyev/interfacebloat v1.1.0 // indirect - github.com/sashamelentyev/usestdlibvars v1.27.0 // indirect - github.com/securego/gosec/v2 v2.21.2 // indirect - github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/sivchari/containedctx v1.0.3 // indirect - github.com/sivchari/tenv v1.10.0 // indirect - github.com/sonatard/noctx v0.0.2 // indirect - github.com/sourcegraph/go-diff v0.7.0 // indirect - github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/cobra v1.8.1 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.12.0 // indirect - github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect - github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/subosito/gotenv v1.4.1 // indirect - github.com/tdakkota/asciicheck v0.2.0 // indirect - github.com/tetafro/godot v1.4.17 // indirect - github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect - github.com/timonwong/loggercheck v0.9.4 // indirect github.com/tinylib/msgp v1.2.5 // indirect - github.com/tomarrell/wrapcheck/v2 v2.9.0 // indirect - github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect - github.com/ultraware/funlen v0.1.0 // indirect - github.com/ultraware/whitespace v0.1.1 // indirect - github.com/uudashr/gocognit v1.1.3 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/wiggin77/merror v1.0.5 // indirect github.com/wiggin77/srslog v1.0.1 // indirect - github.com/xen0n/gosmopolitan v1.2.2 // indirect - github.com/yagipy/maintidx v1.0.0 // indirect - github.com/yeya24/promlinter v0.3.0 // indirect - github.com/ykadowak/zerologlint v0.1.5 // indirect - gitlab.com/bosi/decorder v0.4.2 // indirect - go-simpler.org/musttag v0.12.2 // indirect - go-simpler.org/sloglint v0.7.2 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/automaxprocs v1.5.3 // indirect - go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.32.0 // indirect - golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect - golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f // indirect golang.org/x/mod v0.22.0 // indirect golang.org/x/net v0.34.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.29.0 // indirect - golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/tools v0.29.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47 // indirect google.golang.org/grpc v1.70.0 // indirect google.golang.org/protobuf v1.36.4 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gotest.tools/gotestsum v1.7.0 // indirect - honnef.co/go/tools v0.5.1 // indirect mellium.im/reader v0.1.0 // indirect mellium.im/xmlstream v0.15.4 // indirect - mvdan.cc/gofumpt v0.7.0 // indirect - mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect -) - -tool ( - github.com/golangci/golangci-lint/cmd/golangci-lint - gotest.tools/gotestsum ) diff --git a/go.sum b/go.sum index 9a27f5c..4e30588 100644 --- a/go.sum +++ b/go.sum @@ -1,345 +1,79 @@ -4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA= -4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= -4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc= -4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8= -github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0= -github.com/Abirdcfly/dupword v0.1.1 h1:Bsxe0fIw6OwBtXMIncaTxCLHYO5BB+3mcsR5E8VXloY= -github.com/Abirdcfly/dupword v0.1.1/go.mod h1:B49AcJdTYYkpd4HjgAcutNGG9HZ2JWwKunH9Y2BA6sM= -github.com/Antonboom/errname v0.1.13 h1:JHICqsewj/fNckzrfVSe+T33svwQxmjC+1ntDsHOVvM= -github.com/Antonboom/errname v0.1.13/go.mod h1:uWyefRYRN54lBg6HseYCFhs6Qjcy41Y3Jl/dVhA87Ns= -github.com/Antonboom/nilnil v0.1.9 h1:eKFMejSxPSA9eLSensFmjW2XTgTwJMjZ8hUHtV4s/SQ= -github.com/Antonboom/nilnil v0.1.9/go.mod h1:iGe2rYwCq5/Me1khrysB4nwI7swQvjclR8/YRPl5ihQ= -github.com/Antonboom/testifylint v1.4.3 h1:ohMt6AHuHgttaQ1xb6SSnxCeK4/rnK7KKzbvs7DmEck= -github.com/Antonboom/testifylint v1.4.3/go.mod h1:+8Q9+AOLsz5ZiQiiYujJKs9mNz398+M6UgslP4qgJLA= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs= -github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Crocmagnon/fatcontext v0.5.2 h1:vhSEg8Gqng8awhPju2w7MKHqMlg4/NI+gSDHtR3xgwA= -github.com/Crocmagnon/fatcontext v0.5.2/go.mod h1:87XhRMaInHP44Q7Tlc7jkgKKB7kZAOPiDkFMdKCC+74= -github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= -github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= -github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC23cV0kEsN1MVMNqeOW43cU= -github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0/go.mod h1:ONJg5sxcbsdQQ4pOW8TGdTidT2TMAUy/2Xhr8mrYaao= -github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= -github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= -github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA= -github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ= -github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= -github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= -github.com/alecthomas/go-check-sumtype v0.1.4 h1:WCvlB3l5Vq5dZQTFmodqL2g68uHiSwwlWcT5a2FGK0c= -github.com/alecthomas/go-check-sumtype v0.1.4/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ= -github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= -github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alexkohler/nakedret/v2 v2.0.4 h1:yZuKmjqGi0pSmjGpOC016LtPJysIL0WEUiaXW5SUnNg= -github.com/alexkohler/nakedret/v2 v2.0.4/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU= -github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= -github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= -github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= -github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY= -github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= -github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= -github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bkielbasa/cyclop v1.2.1 h1:AeF71HZDob1P2/pRm1so9cd1alZnrpyc4q2uP2l0gJY= -github.com/bkielbasa/cyclop v1.2.1/go.mod h1:K/dT/M0FPAiYjBgQGau7tz+3TMh4FWAEqlMhzFWCrgM= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= -github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= -github.com/bombsimon/wsl/v4 v4.4.1 h1:jfUaCkN+aUpobrMO24zwyAMwMAV5eSziCkOKEauOLdw= -github.com/bombsimon/wsl/v4 v4.4.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= -github.com/breml/bidichk v0.2.7 h1:dAkKQPLl/Qrk7hnP6P+E0xOodrq8Us7+U0o4UBOAlQY= -github.com/breml/bidichk v0.2.7/go.mod h1:YodjipAGI9fGcYM7II6wFvGhdMYsC5pHDlGzqvEW3tQ= -github.com/breml/errchkjson v0.3.6 h1:VLhVkqSBH96AvXEyclMR37rZslRrY2kcyq+31HCsVrA= -github.com/breml/errchkjson v0.3.6/go.mod h1:jhSDoFheAF2RSDOlCfhHO9KqhZgAYLyvHe7bRCX8f/U= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= -github.com/butuzov/ireturn v0.3.0 h1:hTjMqWw3y5JC3kpnC5vXmFJAWI/m31jaCYQqzkS6PL0= -github.com/butuzov/ireturn v0.3.0/go.mod h1:A09nIiwiqzN/IoVo9ogpa0Hzi9fex1kd9PSD6edP5ZA= -github.com/butuzov/mirror v1.2.0 h1:9YVK1qIjNspaqWutSv8gsge2e/Xpq1eqEkslEUHy5cs= -github.com/butuzov/mirror v1.2.0/go.mod h1:DqZZDtzm42wIAIyHXeN8W/qb1EPlb9Qn/if9icBOpdQ= -github.com/catenacyber/perfsprint v0.7.1 h1:PGW5G/Kxn+YrN04cRAZKC+ZuvlVwolYMrIyyTJ/rMmc= -github.com/catenacyber/perfsprint v0.7.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50= -github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg= -github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4= -github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= -github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc= -github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/ckaznocha/intrange v0.2.0 h1:FykcZuJ8BD7oX93YbO1UY9oZtkRbp+1/kJcDjkefYLs= -github.com/ckaznocha/intrange v0.2.0/go.mod h1:r5I7nUlAAG56xmkOpw4XVr16BXhwYTUdcuRFeevn1oE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= -github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= -github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c= -github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= -github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= -github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk= -github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dyatlov/go-opengraph/opengraph v0.0.0-20220524092352-606d7b1e5f8a h1:etIrTD8BQqzColk9nKRusM9um5+1q0iOEJLqfBMIK64= github.com/dyatlov/go-opengraph/opengraph v0.0.0-20220524092352-606d7b1e5f8a/go.mod h1:emQhSYTXqB0xxjLITTw4EaWZ+8IIQYw+kx9GqNUKdLg= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= -github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= -github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= -github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA= -github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= -github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghostiam/protogetter v0.3.6 h1:R7qEWaSgFCsy20yYHNIJsU9ZOb8TziSRRxuAOTVKeOk= -github.com/ghostiam/protogetter v0.3.6/go.mod h1:7lpeDnEJ1ZjL/YtyoN99ljO4z0pd3H0d18/t2dPBxHw= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk= github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-critic/go-critic v0.11.4 h1:O7kGOCx0NDIni4czrkRIXTnit0mkyKOCePh3My6OyEU= -github.com/go-critic/go-critic v0.11.4/go.mod h1:2QAdo4iuLik5S9YG0rT4wcZ8QxwHYkrr6/2MWAiv/vc= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= -github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= -github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= -github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s= -github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= -github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= -github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= -github.com/go-toolsmith/astequal v1.2.0 h1:3Fs3CYZ1k9Vo4FzFhwwewC3CHISHDnVUPC4x0bI2+Cw= -github.com/go-toolsmith/astequal v1.2.0/go.mod h1:c8NZ3+kSFtFY/8lPso4v8LuJjdJiUFVnSuU3s0qrrDY= -github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco= -github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= -github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA= -github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= -github.com/go-toolsmith/pkgload v1.2.2 h1:0CtmHq/02QhxcF7E9N5LIFcYFsMR5rdovfqTtRKkgIk= -github.com/go-toolsmith/pkgload v1.2.2/go.mod h1:R2hxLNRKuAsiXCo2i5J6ZQPhnPMOVtU+f0arbFPWCus= -github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= -github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw= -github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= -github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= -github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= -github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= -github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= -github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= -github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= -github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= -github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= -github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 h1:/1322Qns6BtQxUZDTAT4SdcoxknUki7IAoK4SAXr8ME= -github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9/go.mod h1:Oesb/0uFAyWoaw1U1qS5zyjCg5NP9C9iwjnI4tIsXEE= -github.com/golangci/golangci-lint v1.61.0 h1:VvbOLaRVWmyxCnUIMTbf1kDsaJbTzH20FAMXTAlQGu8= -github.com/golangci/golangci-lint v1.61.0/go.mod h1:e4lztIrJJgLPhWvFPDkhiMwEFRrWlmFbrZea3FsJyN8= -github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs= -github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo= -github.com/golangci/modinfo v0.3.4 h1:oU5huX3fbxqQXdfspamej74DFX0kyGLkw1ppvXoJ8GA= -github.com/golangci/modinfo v0.3.4/go.mod h1:wytF1M5xl9u0ij8YSvhkEVPP3M5Mc7XLl1pxH3B2aUM= -github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c= -github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc= -github.com/golangci/revgrep v0.5.3 h1:3tL7c1XBMtWHHqVpS5ChmiAAoe4PF/d5+ULzV9sLAzs= -github.com/golangci/revgrep v0.5.3/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= -github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs= -github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= -github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s= -github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= -github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= -github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= -github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q= -github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= -github.com/gostaticanalysis/forcetypeassert v0.1.0 h1:6eUflI3DiGusXGK6X7cCcIgVCpZ2CiZ1Q7jl6ZxNV70= -github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak= -github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk= -github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= -github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= -github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= -github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -351,94 +85,25 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg= github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= -github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= -github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= -github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= -github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= -github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= -github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= -github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= -github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= -github.com/jjti/go-spancheck v0.6.2 h1:iYtoxqPMzHUPp7St+5yA8+cONdyXD3ug6KK15n7Pklk= -github.com/jjti/go-spancheck v0.6.2/go.mod h1:+X7lvIrR5ZdUTkxFYqzJ0abr8Sb5LOo80uOhWNqIrYA= -github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= -github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= -github.com/karamaru-alpha/copyloopvar v1.1.0 h1:x7gNyKcC2vRBO1H2Mks5u1VxQtYvFiym7fCjIP8RPos= -github.com/karamaru-alpha/copyloopvar v1.1.0/go.mod h1:u7CIfztblY0jZLOQZgH3oYsJzpC2A7S6u/lfgSXHy0k= -github.com/kisielk/errcheck v1.7.0 h1:+SbscKmWJ5mOK/bO1zS60F5I9WwZDWOfRsC4RwfwRV0= -github.com/kisielk/errcheck v1.7.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LXxiilg= -github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= -github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= -github.com/kunwardeep/paralleltest v1.0.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs= -github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= -github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ= -github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA= -github.com/lasiar/canonicalheader v1.1.1 h1:wC+dY9ZfiqiPwAexUApFush/csSPXeIi4QqyxXmng8I= -github.com/lasiar/canonicalheader v1.1.1/go.mod h1:cXkb3Dlk6XXy+8MVQnF23CYKWlyA7kfQhSw2CcZtZb0= -github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJZ3alg= -github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g= -github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo= -github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= -github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= -github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= -github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= -github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk= -github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= -github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= -github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04= -github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= -github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE= -github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= -github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= -github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 h1:Khvh6waxG1cHc4Cz5ef9n3XVCxRWpAKUtqg9PJl5+y8= github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404/go.mod h1:RyS7FDNQlzF1PsjbJWHRI35exqaKGSO9qD4iv8QjE34= github.com/mattermost/ldap v0.0.0-20231116144001-0f480c025956 h1:Y1Tu/swM31pVwwb2BTCsOdamENjjWCI6qmfHLbk6OZI= @@ -447,7 +112,6 @@ github.com/mattermost/logr/v2 v2.0.21 h1:CMHsP+nrbRlEC4g7BwOk1GAnMtHkniFhlSQPXy5 github.com/mattermost/logr/v2 v2.0.21/go.mod h1:kZkB/zqKL9e+RY5gB3vGpsyenC+TpuiOenjMkvJJbzc= github.com/mattermost/mattermost/server/public v0.1.10 h1:gp3XHxqj5KDkz3venimqqNc62rqyF15uusQuBr8k7J4= github.com/mattermost/mattermost/server/public v0.1.10/go.mod h1:hu2sIyXm024PGIGhACqmCxvp3atrwRzXGgAzCvs6zJs= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= @@ -456,129 +120,36 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A= -github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI= -github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= -github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg= -github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= -github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= -github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= -github.com/nunnatsa/ginkgolinter v0.16.2 h1:8iLqHIZvN4fTLDC0Ke9tbSZVcyVHoBs0HIbnVSxfHJk= -github.com/nunnatsa/ginkgolinter v0.16.2/go.mod h1:4tWRinDN1FeJgU+iJANW/kz7xKN5nYRAOfJDQUS9dOQ= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= -github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= -github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= -github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= -github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= -github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= -github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= -github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= -github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= -github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= -github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY= github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polyfloyd/go-errorlint v1.6.0 h1:tftWV9DE7txiFzPpztTAwyoRLKNj9gpVm2cg8/OwcYY= -github.com/polyfloyd/go-errorlint v1.6.0/go.mod h1:HR7u8wuP1kb1NeN1zqTd1ZMlqUKPPHF+Id4vIPvDqVw= -github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 h1:+Wl/0aFp0hpuHM3H//KMft64WQ1yX9LdJY64Qm/gFCo= -github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI= -github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= -github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= -github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= -github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= -github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= -github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= -github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= -github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU= -github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE= -github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= -github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= -github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc= -github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= -github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= -github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= -github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= -github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= -github.com/sashamelentyev/usestdlibvars v1.27.0 h1:t/3jZpSXtRPRf2xr0m63i32ZrusyurIGT9E5wAvXQnI= -github.com/sashamelentyev/usestdlibvars v1.27.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8= -github.com/securego/gosec/v2 v2.21.2 h1:deZp5zmYf3TWwU7A7cR2+SolbTpZ3HQiwFqnzQyEl3M= -github.com/securego/gosec/v2 v2.21.2/go.mod h1:au33kg78rNseF5PwPnTWhuYBFf534bvJRvOrgZ/bFzU= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= -github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= @@ -601,83 +172,22 @@ github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1l github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= -github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= -github.com/sivchari/tenv v1.10.0 h1:g/hzMA+dBCKqGXgW8AV/1xIWhAvDrx0zFKNR48NFMg0= -github.com/sivchari/tenv v1.10.0/go.mod h1:tdY24masnVoZFxYrHv/nD6Tc8FbkEtAQEEziXpyMgqY= -github.com/sonatard/noctx v0.0.2 h1:L7Dz4De2zDQhW8S0t+KUjY0MAQJd6SgVwhzNIc4ok00= -github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= -github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= -github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= -github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= -github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= -github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= -github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= -github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= -github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc= -github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= -github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM= -github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg= -github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= -github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= -github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= -github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= -github.com/tetafro/godot v1.4.17 h1:pGzu+Ye7ZUEFx7LHU0dAKmCOXWsPjl7qA6iMGndsjPs= -github.com/tetafro/godot v1.4.17/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= -github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M= -github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= -github.com/timonwong/loggercheck v0.9.4 h1:HKKhqrjcVj8sxL7K77beXh0adEm6DLjV/QOGeMXEVi4= -github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg= github.com/tinylib/msgp v1.2.5 h1:WeQg1whrXRFiZusidTQqzETkRpGjFjcIhW6uqWH09po= github.com/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= -github.com/tomarrell/wrapcheck/v2 v2.9.0 h1:801U2YCAjLhdN8zhZ/7tdjB3EnAoRlJHt/s+9hijLQ4= -github.com/tomarrell/wrapcheck/v2 v2.9.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo= -github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= -github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= -github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81vI= -github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4= -github.com/ultraware/whitespace v0.1.1 h1:bTPOGejYFulW3PkcrqkeQwOd6NKOOXvmGD9bo/Gk8VQ= -github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= -github.com/uudashr/gocognit v1.1.3 h1:l+a111VcDbKfynh+airAy/DJQKaXh2m9vkoysMPSZyM= -github.com/uudashr/gocognit v1.1.3/go.mod h1:aKH8/e8xbTRBwjbCkwZ8qt4l2EpKXl31KMHgSS+lZ2U= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= @@ -688,35 +198,8 @@ github.com/wiggin77/merror v1.0.5 h1:P+lzicsn4vPMycAf2mFf7Zk6G9eco5N+jB1qJ2XW3ME github.com/wiggin77/merror v1.0.5/go.mod h1:H2ETSu7/bPE0Ymf4bEwdUoo73OOEkdClnoRisfw0Nm0= github.com/wiggin77/srslog v1.0.1 h1:gA2XjSMy3DrRdX9UqLuDtuVAAshb8bE1NhX1YK0Qe+8= github.com/wiggin77/srslog v1.0.1/go.mod h1:fehkyYDq1QfuYn60TDPu9YdY2bB85VUW2mvN1WynEls= -github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU= -github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg= -github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= -github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= -github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs= -github.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+YcPQN+mW4= -github.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw= -github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= -gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= -go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= -go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= -go-simpler.org/musttag v0.12.2 h1:J7lRc2ysXOq7eM8rwaTYnNrHd5JwjppzB6mScysB2Cs= -go-simpler.org/musttag v0.12.2/go.mod h1:uN1DVIasMTQKk6XSik7yrJoEysGtR2GRqvWnI9S7TYM= -go-simpler.org/sloglint v0.7.2 h1:Wc9Em/Zeuu7JYpl+oKoYOsQSy2X560aVueCW/m6IijY= -go-simpler.org/sloglint v0.7.2/go.mod h1:US+9C80ppl7VsThQclkM7BkCHQAzuz8kHLsW3ppuluo= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= @@ -727,75 +210,19 @@ go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiy go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= -go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk= -golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= -golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8= -golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -803,356 +230,109 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= -golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= -golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47 h1:91mG8dNTpkC0uChJUQ9zCiRqx3GEEFOWaRZ0mI6Oj2I= google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/gotestsum v1.7.0 h1:RwpqwwFKBAa2h+F6pMEGpE707Edld0etUD3GhqqhDNc= -gotest.tools/gotestsum v1.7.0/go.mod h1:V1m4Jw3eBerhI/A6qCxUE07RnCg7ACkKj9BYcAm09V8= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I= -honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs= mellium.im/reader v0.1.0 h1:UUEMev16gdvaxxZC7fC08j7IzuDKh310nB6BlwnxTww= mellium.im/reader v0.1.0/go.mod h1:F+X5HXpkIfJ9EE1zHQG9lM/hO946iYAmU7xjg5dsQHI= mellium.im/sasl v0.3.2 h1:PT6Xp7ccn9XaXAnJ03FcEjmAn7kK1x7aoXV6F+Vmrl0= @@ -1161,12 +341,5 @@ mellium.im/xmlstream v0.15.4 h1:gLKxcWl4rLMUpKgtzrTBvr4OexPeO/edYus+uK3F6ZI= mellium.im/xmlstream v0.15.4/go.mod h1:yXaCW2++fmVO4L9piKVkyLDqnCmictVYF7FDQW8prb4= mellium.im/xmpp v0.22.0 h1:UthQVSwEAr7SNrmyc90c2ykGpVHxjn/3yw8Ey4+Im8s= mellium.im/xmpp v0.22.0/go.mod h1:WSjq12nhREFD88Vy/0WD6Q8inE8t6a8w7QjzwivWitw= -mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU= -mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo= -mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U= -mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/plugin.json b/plugin.json index 4a1f690..fbf764e 100644 --- a/plugin.json +++ b/plugin.json @@ -1,12 +1,12 @@ { - "id": "com.mattermost.plugin-bridge-xmpp", + "id": "com.mattermost.bridge-xmpp", "name": "Mattermost Bridge for XMPP", "description": "This plugin provides a bridge connecting Mattermost and XMPP servers.", "homepage_url": "https://github.com/mattermost/mattermost-plugin-bridge-xmpp", "support_url": "https://github.com/mattermost/mattermost-plugin-bridge-xmpp/issues", "icon_path": "assets/logo.png", "version": "", - "min_server_version": "9.5.0", + "min_server_version": "6.2.1", "server": { "executables": { "darwin-amd64": "server/dist/plugin-darwin-amd64", @@ -29,40 +29,28 @@ "display_name": "XMPP Server URL", "type": "text", "help_text": "The URL of the XMPP server to connect to (e.g., xmpp.example.com:5222)", - "placeholder": "xmpp.example.com:5222", - "default": null, - "hosting": "", - "secret": false + "placeholder": "xmpp.example.com:5222" }, { "key": "XMPPUsername", "display_name": "XMPP Username", "type": "text", "help_text": "The username for authenticating with the XMPP server", - "placeholder": "bridge@xmpp.example.com", - "default": null, - "hosting": "", - "secret": false + "placeholder": "bridge@xmpp.example.com" }, { "key": "XMPPPassword", "display_name": "XMPP Password", "type": "text", - "help_text": "The password for authenticating with the XMPP server", - "placeholder": "", - "default": null, - "hosting": "", - "secret": true + "secret": true, + "help_text": "The password for authenticating with the XMPP server" }, { "key": "EnableSync", "display_name": "Enable Message Synchronization", "type": "bool", "help_text": "When enabled, messages will be synchronized between Mattermost and XMPP", - "placeholder": "", - "default": false, - "hosting": "", - "secret": false + "default": false }, { "key": "XMPPUsernamePrefix", @@ -70,9 +58,7 @@ "type": "text", "help_text": "Prefix for XMPP users in Mattermost (e.g., 'xmpp' creates usernames like 'xmpp:user@domain')", "placeholder": "xmpp", - "default": "xmpp", - "hosting": "", - "secret": false + "default": "xmpp" }, { "key": "XMPPResource", @@ -80,26 +66,20 @@ "type": "text", "help_text": "XMPP resource identifier for the bridge client", "placeholder": "mattermost-bridge", - "default": "mattermost-bridge", - "hosting": "", - "secret": false + "default": "mattermost-bridge" }, { "key": "XMPPInsecureSkipVerify", "display_name": "Skip TLS Certificate Verification", "type": "bool", "help_text": "Skip TLS certificate verification for XMPP connections (use only for testing/development)", - "placeholder": "", - "default": false, - "hosting": "", - "secret": false + "default": false } - ], - "sections": null + ] }, "props": { "pluginctl": { - "version": "v0.1.2" + "version": "v0.1.1" } } } \ No newline at end of file diff --git a/server/bridge/manager.go b/server/bridge/manager.go index 1137368..588aa81 100644 --- a/server/bridge/manager.go +++ b/server/bridge/manager.go @@ -6,38 +6,29 @@ import ( "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/logger" "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/model" - mmModel "github.com/mattermost/mattermost/server/public/model" - "github.com/mattermost/mattermost/server/public/plugin" ) -// BridgeManager manages multiple bridge instances -type BridgeManager struct { - bridges map[string]model.Bridge - mu sync.RWMutex - logger logger.Logger - api plugin.API - remoteID string +// Manager manages multiple bridge instances +type Manager struct { + bridges map[string]model.Bridge + mu sync.RWMutex + logger logger.Logger } -// NewBridgeManager creates a new bridge manager -func NewBridgeManager(logger logger.Logger, api plugin.API, remoteID string) model.BridgeManager { +// NewManager creates a new bridge manager +func NewManager(logger logger.Logger) model.BridgeManager { if logger == nil { panic("logger cannot be nil") } - if api == nil { - panic("plugin API cannot be nil") - } - return &BridgeManager{ - bridges: make(map[string]model.Bridge), - logger: logger, - api: api, - remoteID: remoteID, + return &Manager{ + bridges: make(map[string]model.Bridge), + logger: logger, } } // RegisterBridge registers a bridge with the manager -func (m *BridgeManager) RegisterBridge(name string, bridge model.Bridge) error { +func (m *Manager) RegisterBridge(name string, bridge model.Bridge) error { if name == "" { return fmt.Errorf("bridge name cannot be empty") } @@ -59,7 +50,7 @@ func (m *BridgeManager) RegisterBridge(name string, bridge model.Bridge) error { } // StartBridge starts a specific bridge -func (m *BridgeManager) StartBridge(name string) error { +func (m *Manager) StartBridge(name string) error { m.mu.RLock() bridge, exists := m.bridges[name] m.mu.RUnlock() @@ -80,7 +71,7 @@ func (m *BridgeManager) StartBridge(name string) error { } // StopBridge stops a specific bridge -func (m *BridgeManager) StopBridge(name string) error { +func (m *Manager) StopBridge(name string) error { m.mu.RLock() bridge, exists := m.bridges[name] m.mu.RUnlock() @@ -101,7 +92,7 @@ func (m *BridgeManager) StopBridge(name string) error { } // UnregisterBridge removes a bridge from the manager -func (m *BridgeManager) UnregisterBridge(name string) error { +func (m *Manager) UnregisterBridge(name string) error { m.mu.Lock() defer m.mu.Unlock() @@ -124,7 +115,7 @@ func (m *BridgeManager) UnregisterBridge(name string) error { } // GetBridge retrieves a bridge by name -func (m *BridgeManager) GetBridge(name string) (model.Bridge, error) { +func (m *Manager) GetBridge(name string) (model.Bridge, error) { m.mu.RLock() defer m.mu.RUnlock() @@ -137,7 +128,7 @@ func (m *BridgeManager) GetBridge(name string) (model.Bridge, error) { } // ListBridges returns a list of all registered bridge names -func (m *BridgeManager) ListBridges() []string { +func (m *Manager) ListBridges() []string { m.mu.RLock() defer m.mu.RUnlock() @@ -150,7 +141,7 @@ func (m *BridgeManager) ListBridges() []string { } // HasBridge checks if a bridge with the given name is registered -func (m *BridgeManager) HasBridge(name string) bool { +func (m *Manager) HasBridge(name string) bool { m.mu.RLock() defer m.mu.RUnlock() @@ -159,7 +150,7 @@ func (m *BridgeManager) HasBridge(name string) bool { } // HasBridges checks if any bridges are registered -func (m *BridgeManager) HasBridges() bool { +func (m *Manager) HasBridges() bool { m.mu.RLock() defer m.mu.RUnlock() @@ -167,7 +158,7 @@ func (m *BridgeManager) HasBridges() bool { } // Shutdown stops and unregisters all bridges -func (m *BridgeManager) Shutdown() error { +func (m *Manager) Shutdown() error { m.mu.Lock() defer m.mu.Unlock() @@ -196,7 +187,7 @@ func (m *BridgeManager) Shutdown() error { } // OnPluginConfigurationChange propagates configuration changes to all registered bridges -func (m *BridgeManager) OnPluginConfigurationChange(config any) error { +func (m *Manager) OnPluginConfigurationChange(config any) error { m.mu.RLock() defer m.mu.RUnlock() @@ -222,185 +213,4 @@ func (m *BridgeManager) OnPluginConfigurationChange(config any) error { m.logger.LogInfo("Configuration changes propagated to all bridges") return nil -} - -// CreateChannelMapping handles the creation of a channel mapping by calling the appropriate bridge -func (m *BridgeManager) CreateChannelMapping(req model.CreateChannelMappingRequest) error { - // Validate request - if err := req.Validate(); err != nil { - return fmt.Errorf("invalid mapping request: %w", err) - } - - m.logger.LogDebug("Creating channel mapping", "channel_id", req.ChannelID, "bridge_name", req.BridgeName, "bridge_room_id", req.BridgeRoomID, "user_id", req.UserID, "team_id", req.TeamID) - - // Get the specific bridge - bridge, err := m.GetBridge(req.BridgeName) - if err != nil { - m.logger.LogError("Failed to get bridge", "bridge_name", req.BridgeName, "error", err) - return fmt.Errorf("failed to get bridge '%s': %w", req.BridgeName, err) - } - - // Check if bridge is connected - if !bridge.IsConnected() { - return fmt.Errorf("bridge '%s' is not connected", req.BridgeName) - } - - // NEW: Check if room already mapped to another channel - existingChannelID, err := bridge.GetRoomMapping(req.BridgeRoomID) - if err != nil { - m.logger.LogError("Failed to check room mapping", "bridge_room_id", req.BridgeRoomID, "error", err) - return fmt.Errorf("failed to check room mapping: %w", err) - } - if existingChannelID != "" { - m.logger.LogWarn("Room already mapped to another channel", - "bridge_room_id", req.BridgeRoomID, - "existing_channel_id", existingChannelID, - "requested_channel_id", req.ChannelID) - return fmt.Errorf("room '%s' is already mapped to channel '%s'", req.BridgeRoomID, existingChannelID) - } - - // NEW: Check if room exists on target bridge - roomExists, err := bridge.RoomExists(req.BridgeRoomID) - if err != nil { - m.logger.LogError("Failed to check room existence", "bridge_room_id", req.BridgeRoomID, "error", err) - return fmt.Errorf("failed to check room existence: %w", err) - } - if !roomExists { - m.logger.LogWarn("Room does not exist on bridge", - "bridge_room_id", req.BridgeRoomID, - "bridge_name", req.BridgeName) - return fmt.Errorf("room '%s' does not exist on %s bridge", req.BridgeRoomID, req.BridgeName) - } - - m.logger.LogDebug("Room validation passed", - "bridge_room_id", req.BridgeRoomID, - "bridge_name", req.BridgeName, - "room_exists", roomExists, - "already_mapped", false) - - // Create the channel mapping on the receiving bridge - if err = bridge.CreateChannelMapping(req.ChannelID, req.BridgeRoomID); err != nil { - m.logger.LogError("Failed to create channel mapping", "channel_id", req.ChannelID, "bridge_name", req.BridgeName, "bridge_room_id", req.BridgeRoomID, "error", err) - return fmt.Errorf("failed to create channel mapping for bridge '%s': %w", req.BridgeName, err) - } - - mattermostBridge, err := m.GetBridge("mattermost") - if err != nil { - m.logger.LogError("Failed to get Mattermost bridge", "error", err) - return fmt.Errorf("failed to get Mattermost bridge: %w", err) - } - - // Create the channel mapping in the Mattermost bridge - if err = mattermostBridge.CreateChannelMapping(req.ChannelID, req.BridgeRoomID); err != nil { - m.logger.LogError("Failed to create channel mapping in Mattermost bridge", "channel_id", req.ChannelID, "bridge_name", req.BridgeName, "bridge_room_id", req.BridgeRoomID, "error", err) - return fmt.Errorf("failed to create channel mapping in Mattermost bridge: %w", err) - } - - // Share the channel using Mattermost's shared channels API - if err = m.shareChannel(req); err != nil { - m.logger.LogError("Failed to share channel", "channel_id", req.ChannelID, "bridge_room_id", req.BridgeRoomID, "error", err) - // Don't fail the entire operation if sharing fails, but log the error - m.logger.LogWarn("Channel mapping created but sharing failed - channel may not sync properly") - } - - m.logger.LogInfo("Successfully created channel mapping", "channel_id", req.ChannelID, "bridge_name", req.BridgeName, "bridge_room_id", req.BridgeRoomID) - return nil -} - -// DeleteChannepMapping handles the deletion of a channel mapping by calling the appropriate bridges -func (m *BridgeManager) DeleteChannepMapping(req model.DeleteChannelMappingRequest) error { - // Validate request - if err := req.Validate(); err != nil { - return fmt.Errorf("invalid delete request: %w", err) - } - - m.logger.LogDebug("Deleting channel mapping", "channel_id", req.ChannelID, "bridge_name", req.BridgeName, "user_id", req.UserID, "team_id", req.TeamID) - - // Get the specific bridge - bridge, err := m.GetBridge(req.BridgeName) - if err != nil { - m.logger.LogError("Failed to get bridge", "bridge_name", req.BridgeName, "error", err) - return fmt.Errorf("failed to get bridge '%s': %w", req.BridgeName, err) - } - - // Check if bridge is connected - if !bridge.IsConnected() { - return fmt.Errorf("bridge '%s' is not connected", req.BridgeName) - } - - // Delete the channel mapping from the specific bridge - if err = bridge.DeleteChannelMapping(req.ChannelID); err != nil { - m.logger.LogError("Failed to delete channel mapping", "channel_id", req.ChannelID, "bridge_name", req.BridgeName, "error", err) - return fmt.Errorf("failed to delete channel mapping for bridge '%s': %w", req.BridgeName, err) - } - - // Also delete from Mattermost bridge to clean up reverse mappings - mattermostBridge, err := m.GetBridge("mattermost") - if err != nil { - m.logger.LogError("Failed to get Mattermost bridge", "error", err) - return fmt.Errorf("failed to get Mattermost bridge: %w", err) - } - - // Delete the channel mapping from the Mattermost bridge - if err = mattermostBridge.DeleteChannelMapping(req.ChannelID); err != nil { - m.logger.LogError("Failed to delete channel mapping from Mattermost bridge", "channel_id", req.ChannelID, "bridge_name", req.BridgeName, "error", err) - return fmt.Errorf("failed to delete channel mapping from Mattermost bridge: %w", err) - } - - // Unshare the channel using Mattermost's shared channels API - if err = m.unshareChannel(req.ChannelID); err != nil { - m.logger.LogError("Failed to unshare channel", "channel_id", req.ChannelID, "error", err) - // Don't fail the entire operation if unsharing fails, but log the error - m.logger.LogWarn("Channel mapping deleted but unsharing failed - channel may still appear as shared") - } - - m.logger.LogInfo("Successfully deleted channel mapping", "channel_id", req.ChannelID, "bridge_name", req.BridgeName) - return nil -} - -// shareChannel creates a shared channel configuration using the Mattermost API -func (m *BridgeManager) shareChannel(req model.CreateChannelMappingRequest) error { - if m.remoteID == "" { - return fmt.Errorf("remote ID not set - plugin not registered for shared channels") - } - - // Create SharedChannel configuration - sharedChannel := &mmModel.SharedChannel{ - ChannelId: req.ChannelID, - TeamId: req.TeamID, - Home: true, - ReadOnly: false, - ShareName: model.SanitizeShareName(fmt.Sprintf("bridge-%s", req.BridgeRoomID)), - ShareDisplayName: fmt.Sprintf("Bridge: %s", req.BridgeRoomID), - SharePurpose: fmt.Sprintf("Shared channel bridged to %s", req.BridgeRoomID), - ShareHeader: "test header", - CreatorId: req.UserID, - RemoteId: m.remoteID, - } - - // Share the channel - sharedChannel, err := m.api.ShareChannel(sharedChannel) - if err != nil { - return fmt.Errorf("failed to share channel via API: %w", err) - } - - m.logger.LogInfo("Successfully shared channel", "channel_id", req.ChannelID, "shared_channel_id", sharedChannel.ChannelId) - return nil -} - -// unshareChannel removes shared channel configuration using the Mattermost API -func (m *BridgeManager) unshareChannel(channelID string) error { - // Unshare the channel - unshared, err := m.api.UnshareChannel(channelID) - if err != nil { - return fmt.Errorf("failed to unshare channel via API: %w", err) - } - - if !unshared { - m.logger.LogWarn("Channel was not shared or already unshared", "channel_id", channelID) - } else { - m.logger.LogInfo("Successfully unshared channel", "channel_id", channelID) - } - - return nil -} +} \ No newline at end of file diff --git a/server/bridge/mattermost/bridge.go b/server/bridge/mattermost/bridge.go deleted file mode 100644 index 79baf6e..0000000 --- a/server/bridge/mattermost/bridge.go +++ /dev/null @@ -1,338 +0,0 @@ -package mattermost - -import ( - "context" - "fmt" - "sync" - "sync/atomic" - - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/bridge" - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/config" - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/logger" - pluginModel "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/model" - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/store/kvstore" - "github.com/mattermost/mattermost/server/public/plugin" -) - -// mattermostBridge handles syncing messages between Mattermost instances -type mattermostBridge struct { - logger logger.Logger - api plugin.API - kvstore kvstore.KVStore - userManager pluginModel.BridgeUserManager - - // Connection management - connected atomic.Bool - ctx context.Context - cancel context.CancelFunc - - // Current configuration - config *config.Configuration - configMu sync.RWMutex - - // Channel mappings cache - channelMappings map[string]string - mappingsMu sync.RWMutex -} - -// NewBridge creates a new Mattermost bridge -func NewBridge(log logger.Logger, api plugin.API, kvstore kvstore.KVStore, cfg *config.Configuration) pluginModel.Bridge { - ctx, cancel := context.WithCancel(context.Background()) - bridge := &mattermostBridge{ - logger: log, - api: api, - kvstore: kvstore, - ctx: ctx, - cancel: cancel, - channelMappings: make(map[string]string), - config: cfg, - userManager: bridge.NewUserManager("mattermost", log), - } - - return bridge -} - -// UpdateConfiguration updates the bridge configuration -func (b *mattermostBridge) UpdateConfiguration(newConfig any) error { - cfg, ok := newConfig.(*config.Configuration) - if !ok { - return fmt.Errorf("invalid configuration type") - } - - b.configMu.Lock() - b.config = cfg - b.configMu.Unlock() - - // Log the configuration change - b.logger.LogInfo("Mattermost bridge configuration updated") - - return nil -} - -// Start initializes the bridge -func (b *mattermostBridge) Start() error { - b.logger.LogDebug("Starting Mattermost bridge") - - b.configMu.RLock() - config := b.config - b.configMu.RUnlock() - - if config == nil { - return fmt.Errorf("bridge configuration not set") - } - - // For Mattermost bridge, we're always "connected" since we're running within Mattermost - b.connected.Store(true) - - // Load existing channel mappings - if err := b.loadChannelMappings(); err != nil { - b.logger.LogWarn("Failed to load some channel mappings", "error", err) - } - - b.logger.LogInfo("Mattermost bridge started successfully") - return nil -} - -// Stop shuts down the bridge -func (b *mattermostBridge) Stop() error { - b.logger.LogInfo("Stopping Mattermost bridge") - - if b.cancel != nil { - b.cancel() - } - - b.connected.Store(false) - b.logger.LogInfo("Mattermost bridge stopped") - return nil -} - -// loadChannelMappings loads existing channel mappings from KV store -func (b *mattermostBridge) loadChannelMappings() error { - b.logger.LogDebug("Loading channel mappings for Mattermost bridge") - - // Get all channel mappings from KV store for Mattermost bridge - mappings, err := b.getAllChannelMappings() - if err != nil { - return fmt.Errorf("failed to load channel mappings: %w", err) - } - - if len(mappings) == 0 { - b.logger.LogInfo("No channel mappings found for Mattermost bridge") - return nil - } - - b.logger.LogInfo("Found channel mappings for Mattermost bridge", "count", len(mappings)) - - // Update local cache - b.mappingsMu.Lock() - for channelID, roomID := range mappings { - b.channelMappings[channelID] = roomID - } - b.mappingsMu.Unlock() - - return nil -} - -// getAllChannelMappings retrieves all channel mappings from KV store for Mattermost bridge -func (b *mattermostBridge) getAllChannelMappings() (map[string]string, error) { - if b.kvstore == nil { - return nil, fmt.Errorf("KV store not initialized") - } - - mappings := make(map[string]string) - - // Get all keys with the Mattermost bridge mapping prefix - mattermostPrefix := kvstore.KeyPrefixChannelMap + "mattermost_" - keys, err := b.kvstore.ListKeysWithPrefix(0, 1000, mattermostPrefix) - if err != nil { - return nil, fmt.Errorf("failed to list Mattermost bridge mapping keys: %w", err) - } - - // Load each mapping - for _, key := range keys { - channelIDBytes, err := b.kvstore.Get(key) - if err != nil { - b.logger.LogWarn("Failed to load mapping for key", "key", key, "error", err) - continue - } - - // Extract room ID from the key - roomID := kvstore.ExtractIdentifierFromChannelMapKey(key, "mattermost") - if roomID == "" { - b.logger.LogWarn("Failed to extract room ID from key", "key", key) - continue - } - - channelID := string(channelIDBytes) - mappings[channelID] = roomID - } - - return mappings, nil -} - -// IsConnected returns whether the bridge is connected -func (b *mattermostBridge) IsConnected() bool { - // Mattermost bridge is always "connected" since it runs within Mattermost - return b.connected.Load() -} - -// Ping actively tests the Mattermost API connectivity -func (b *mattermostBridge) Ping() error { - if !b.connected.Load() { - return fmt.Errorf("Mattermost bridge is not connected") - } - - if b.api == nil { - return fmt.Errorf("Mattermost API not initialized") - } - - b.logger.LogDebug("Testing Mattermost bridge connectivity with API ping") - - // Test API connectivity with a lightweight call - // Using GetServerVersion as it's a simple, read-only operation - version := b.api.GetServerVersion() - if version == "" { - b.logger.LogWarn("Mattermost bridge ping returned empty version") - return fmt.Errorf("Mattermost API ping returned empty server version") - } - - b.logger.LogDebug("Mattermost bridge ping successful", "server_version", version) - return nil -} - -// CreateChannelMapping creates a mapping between a Mattermost channel and another Mattermost room/channel -func (b *mattermostBridge) CreateChannelMapping(channelID, roomID string) error { - if b.kvstore == nil { - return fmt.Errorf("KV store not initialized") - } - - // Store forward and reverse mappings using bridge-agnostic keys - err := b.kvstore.Set(kvstore.BuildChannelMapKey("mattermost", channelID), []byte(roomID)) - if err != nil { - return fmt.Errorf("failed to store channel room mapping: %w", err) - } - - // Update local cache - b.mappingsMu.Lock() - b.channelMappings[channelID] = roomID - b.mappingsMu.Unlock() - - b.logger.LogInfo("Created Mattermost channel room mapping", "channel_id", channelID, "room_id", roomID) - return nil -} - -// GetChannelMapping gets the room ID for a Mattermost channel -func (b *mattermostBridge) GetChannelMapping(channelID string) (string, error) { - // Check cache first - b.mappingsMu.RLock() - roomID, exists := b.channelMappings[channelID] - b.mappingsMu.RUnlock() - - if exists { - return roomID, nil - } - - if b.kvstore == nil { - return "", fmt.Errorf("KV store not initialized") - } - - // Check if we have a mapping in the KV store for this channel ID - roomIDBytes, err := b.kvstore.Get(kvstore.BuildChannelMapKey("mattermost", channelID)) - if err != nil { - return "", nil // Unmapped channels are expected - } - - roomID = string(roomIDBytes) - - // Update cache - b.mappingsMu.Lock() - b.channelMappings[channelID] = roomID - b.mappingsMu.Unlock() - - return roomID, nil -} - -// DeleteChannelMapping removes a mapping between a Mattermost channel and room -func (b *mattermostBridge) DeleteChannelMapping(channelID string) error { - if b.kvstore == nil { - return fmt.Errorf("KV store not initialized") - } - - // Get the room ID from the mapping before deleting - roomID, err := b.GetChannelMapping(channelID) - if err != nil { - return fmt.Errorf("failed to get channel mapping: %w", err) - } - if roomID == "" { - return fmt.Errorf("channel is not mapped to any room") - } - - // Delete forward and reverse mappings from KV store - err = b.kvstore.Delete(kvstore.BuildChannelMapKey("mattermost", channelID)) - if err != nil { - return fmt.Errorf("failed to delete channel room mapping: %w", err) - } - - // Remove from local cache - b.mappingsMu.Lock() - delete(b.channelMappings, channelID) - b.mappingsMu.Unlock() - - b.logger.LogInfo("Deleted Mattermost channel room mapping", "channel_id", channelID, "room_id", roomID) - return nil -} - -// RoomExists checks if a Mattermost channel exists on the server -func (b *mattermostBridge) RoomExists(roomID string) (bool, error) { - if b.api == nil { - return false, fmt.Errorf("Mattermost API not initialized") - } - - b.logger.LogDebug("Checking if Mattermost channel exists", "channel_id", roomID) - - // Use the Mattermost API to check if the channel exists - channel, appErr := b.api.GetChannel(roomID) - if appErr != nil { - if appErr.StatusCode == 404 { - b.logger.LogDebug("Mattermost channel does not exist", "channel_id", roomID) - return false, nil - } - b.logger.LogError("Failed to check channel existence", "channel_id", roomID, "error", appErr) - return false, fmt.Errorf("failed to check channel existence: %w", appErr) - } - - if channel == nil { - b.logger.LogDebug("Mattermost channel does not exist (nil response)", "channel_id", roomID) - return false, nil - } - - b.logger.LogDebug("Mattermost channel exists", "channel_id", roomID, "channel_name", channel.Name) - return true, nil -} - -// GetRoomMapping retrieves the Mattermost channel ID for a given room ID (reverse lookup) -func (b *mattermostBridge) GetRoomMapping(roomID string) (string, error) { - if b.kvstore == nil { - return "", fmt.Errorf("KV store not initialized") - } - - b.logger.LogDebug("Getting channel mapping for Mattermost room", "room_id", roomID) - - // Look up the channel ID using the room ID as the key - channelIDBytes, err := b.kvstore.Get(kvstore.BuildChannelMapKey("mattermost", roomID)) - if err != nil { - // No mapping found is not an error, just return empty string - b.logger.LogDebug("No channel mapping found for room", "room_id", roomID) - return "", nil - } - - channelID := string(channelIDBytes) - b.logger.LogDebug("Found channel mapping for room", "room_id", roomID, "channel_id", channelID) - - return channelID, nil -} - -// GetUserManager returns the user manager for this bridge -func (b *mattermostBridge) GetUserManager() pluginModel.BridgeUserManager { - return b.userManager -} diff --git a/server/bridge/mattermost/user.go b/server/bridge/mattermost/user.go deleted file mode 100644 index 8c4e0bd..0000000 --- a/server/bridge/mattermost/user.go +++ /dev/null @@ -1,300 +0,0 @@ -package mattermost - -import ( - "context" - "fmt" - "sync" - "time" - - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/config" - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/logger" - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/model" - mmModel "github.com/mattermost/mattermost/server/public/model" - "github.com/mattermost/mattermost/server/public/plugin" -) - -// MattermostUser represents a Mattermost user that implements the BridgeUser interface -type MattermostUser struct { - // User identity - id string - displayName string - username string - email string - - // Mattermost API - api plugin.API - - // State management - state model.UserState - stateMu sync.RWMutex - - // Configuration - config *config.Configuration - - // Goroutine lifecycle - ctx context.Context - cancel context.CancelFunc - - // Logger - logger logger.Logger -} - -// NewMattermostUser creates a new Mattermost user -func NewMattermostUser(id, displayName, username, email string, api plugin.API, cfg *config.Configuration, logger logger.Logger) *MattermostUser { - ctx, cancel := context.WithCancel(context.Background()) - - return &MattermostUser{ - id: id, - displayName: displayName, - username: username, - email: email, - api: api, - state: model.UserStateOffline, - config: cfg, - ctx: ctx, - cancel: cancel, - logger: logger, - } -} - -// Validation -func (u *MattermostUser) Validate() error { - if u.id == "" { - return fmt.Errorf("user ID cannot be empty") - } - if u.username == "" { - return fmt.Errorf("username cannot be empty") - } - if u.config == nil { - return fmt.Errorf("configuration cannot be nil") - } - if u.api == nil { - return fmt.Errorf("Mattermost API cannot be nil") - } - return nil -} - -// Identity (bridge-agnostic) -func (u *MattermostUser) GetID() string { - return u.id -} - -func (u *MattermostUser) GetDisplayName() string { - return u.displayName -} - -// State management -func (u *MattermostUser) GetState() model.UserState { - u.stateMu.RLock() - defer u.stateMu.RUnlock() - return u.state -} - -func (u *MattermostUser) SetState(state model.UserState) error { - u.stateMu.Lock() - defer u.stateMu.Unlock() - - u.logger.LogDebug("Changing Mattermost user state", "user_id", u.id, "old_state", u.state, "new_state", state) - u.state = state - - // TODO: Update user status in Mattermost if needed - // This could involve setting custom status or presence indicators - - return nil -} - -// Channel operations (abstracted from rooms/channels/groups) -func (u *MattermostUser) JoinChannel(channelID string) error { - u.logger.LogDebug("Mattermost user joining channel", "user_id", u.id, "channel_id", channelID) - - // Add user to channel - _, appErr := u.api.AddUserToChannel(channelID, u.id, "") - if appErr != nil { - return fmt.Errorf("failed to add Mattermost user %s to channel %s: %w", u.id, channelID, appErr) - } - - u.logger.LogInfo("Mattermost user joined channel", "user_id", u.id, "channel_id", channelID) - return nil -} - -func (u *MattermostUser) LeaveChannel(channelID string) error { - u.logger.LogDebug("Mattermost user leaving channel", "user_id", u.id, "channel_id", channelID) - - // Remove user from channel - appErr := u.api.DeleteChannelMember(channelID, u.id) - if appErr != nil { - return fmt.Errorf("failed to remove Mattermost user %s from channel %s: %w", u.id, channelID, appErr) - } - - u.logger.LogInfo("Mattermost user left channel", "user_id", u.id, "channel_id", channelID) - return nil -} - -func (u *MattermostUser) SendMessageToChannel(channelID, message string) error { - u.logger.LogDebug("Mattermost user sending message to channel", "user_id", u.id, "channel_id", channelID) - - // Create post - post := &mmModel.Post{ - UserId: u.id, - ChannelId: channelID, - Message: message, - } - - // Send post - _, appErr := u.api.CreatePost(post) - if appErr != nil { - return fmt.Errorf("failed to send message to Mattermost channel %s: %w", channelID, appErr) - } - - u.logger.LogDebug("Mattermost user sent message to channel", "user_id", u.id, "channel_id", channelID) - return nil -} - -// Connection lifecycle -func (u *MattermostUser) Connect() error { - u.logger.LogDebug("Connecting Mattermost user", "user_id", u.id, "username", u.username) - - // For Mattermost users, "connecting" means verifying the user exists and is accessible - user, appErr := u.api.GetUser(u.id) - if appErr != nil { - return fmt.Errorf("failed to verify Mattermost user %s: %w", u.id, appErr) - } - - // Update user information if it has changed - if user.GetDisplayName("") != u.displayName { - u.displayName = user.GetDisplayName("") - u.logger.LogDebug("Updated Mattermost user display name", "user_id", u.id, "display_name", u.displayName) - } - - u.logger.LogInfo("Mattermost user connected", "user_id", u.id, "username", u.username) - - // Update state to online - _ = u.SetState(model.UserStateOnline) - - return nil -} - -func (u *MattermostUser) Disconnect() error { - u.logger.LogDebug("Disconnecting Mattermost user", "user_id", u.id, "username", u.username) - - // For Mattermost users, "disconnecting" is mostly a state change - // The user still exists in Mattermost, but we're not actively managing them - - _ = u.SetState(model.UserStateOffline) - - u.logger.LogInfo("Mattermost user disconnected", "user_id", u.id, "username", u.username) - return nil -} - -func (u *MattermostUser) IsConnected() bool { - return u.GetState() == model.UserStateOnline -} - -func (u *MattermostUser) Ping() error { - if u.api == nil { - return fmt.Errorf("Mattermost API not initialized for user %s", u.id) - } - - // Test API connectivity by getting server version - version := u.api.GetServerVersion() - if version == "" { - return fmt.Errorf("Mattermost API ping returned empty server version for user %s", u.id) - } - - return nil -} - -// CheckChannelExists checks if a Mattermost channel exists -func (u *MattermostUser) CheckChannelExists(channelID string) (bool, error) { - if u.api == nil { - return false, fmt.Errorf("Mattermost API not initialized for user %s", u.id) - } - - // Try to get the channel by ID - _, appErr := u.api.GetChannel(channelID) - if appErr != nil { - // Check if it's a "not found" error - if appErr.StatusCode == 404 { - return false, nil // Channel doesn't exist - } - return false, fmt.Errorf("failed to check channel existence: %w", appErr) - } - - return true, nil -} - -// Goroutine lifecycle -func (u *MattermostUser) Start(ctx context.Context) error { - u.logger.LogDebug("Starting Mattermost user", "user_id", u.id, "username", u.username) - - // Update context - u.ctx = ctx - - // Connect to verify user exists - if err := u.Connect(); err != nil { - return fmt.Errorf("failed to start Mattermost user %s: %w", u.id, err) - } - - // Start monitoring in a goroutine - go u.monitor() - - u.logger.LogInfo("Mattermost user started", "user_id", u.id, "username", u.username) - return nil -} - -func (u *MattermostUser) Stop() error { - u.logger.LogDebug("Stopping Mattermost user", "user_id", u.id, "username", u.username) - - // Cancel context to stop goroutines - if u.cancel != nil { - u.cancel() - } - - // Disconnect - if err := u.Disconnect(); err != nil { - u.logger.LogWarn("Error disconnecting Mattermost user during stop", "user_id", u.id, "error", err) - } - - u.logger.LogInfo("Mattermost user stopped", "user_id", u.id, "username", u.username) - return nil -} - -// monitor periodically checks the user's status and updates information -func (u *MattermostUser) monitor() { - u.logger.LogDebug("Starting monitor for Mattermost user", "user_id", u.id) - - // Simple monitoring - check user exists periodically - for { - select { - case <-u.ctx.Done(): - u.logger.LogDebug("Monitor stopped for Mattermost user", "user_id", u.id) - return - default: - // Wait before next check - timeoutCtx, cancel := context.WithTimeout(u.ctx, 60*time.Second) - select { - case <-u.ctx.Done(): - cancel() - return - case <-timeoutCtx.Done(): - cancel() - continue - } - } - } -} - -// GetUsername returns the Mattermost username for this user (Mattermost-specific method) -func (u *MattermostUser) GetUsername() string { - return u.username -} - -// GetEmail returns the Mattermost email for this user (Mattermost-specific method) -func (u *MattermostUser) GetEmail() string { - return u.email -} - -// GetAPI returns the Mattermost API instance (for advanced operations) -func (u *MattermostUser) GetAPI() plugin.API { - return u.api -} diff --git a/server/bridge/user.go b/server/bridge/user.go deleted file mode 100644 index e565eb9..0000000 --- a/server/bridge/user.go +++ /dev/null @@ -1,188 +0,0 @@ -package bridge - -import ( - "context" - "fmt" - "sync" - - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/config" - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/logger" - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/model" -) - -// Manager implements the BridgeUserManager interface with bridge-agnostic logic -type UserManager struct { - bridgeType string - logger logger.Logger - users map[string]model.BridgeUser - mu sync.RWMutex - ctx context.Context - cancel context.CancelFunc -} - -// NewUserManager creates a new user manager for a specific bridge type -func NewUserManager(bridgeType string, logger logger.Logger) model.BridgeUserManager { - ctx, cancel := context.WithCancel(context.Background()) - return &UserManager{ - bridgeType: bridgeType, - logger: logger, - users: make(map[string]model.BridgeUser), - ctx: ctx, - cancel: cancel, - } -} - -// CreateUser adds a user to the bridge system -func (m *UserManager) CreateUser(user model.BridgeUser) error { - // Validate the user first - if err := user.Validate(); err != nil { - return fmt.Errorf("invalid user: %w", err) - } - - userID := user.GetID() - - m.mu.Lock() - defer m.mu.Unlock() - - // Check if user already exists - if _, exists := m.users[userID]; exists { - return fmt.Errorf("user %s already exists", userID) - } - - m.logger.LogDebug("Adding bridge user", "bridge_type", m.bridgeType, "user_id", userID, "display_name", user.GetDisplayName()) - - // Store the user - m.users[userID] = user - - m.logger.LogInfo("Bridge user added successfully", "bridge_type", m.bridgeType, "user_id", userID) - return nil -} - -// GetUser retrieves a user by ID -func (m *UserManager) GetUser(userID string) (model.BridgeUser, error) { - m.mu.RLock() - defer m.mu.RUnlock() - - user, exists := m.users[userID] - if !exists { - return nil, fmt.Errorf("user %s not found", userID) - } - - return user, nil -} - -// DeleteUser removes a user from the bridge system -func (m *UserManager) DeleteUser(userID string) error { - m.mu.Lock() - defer m.mu.Unlock() - - user, exists := m.users[userID] - if !exists { - return fmt.Errorf("user %s not found", userID) - } - - m.logger.LogDebug("Deleting bridge user", "bridge_type", m.bridgeType, "user_id", userID) - - // Stop the user first - if err := user.Stop(); err != nil { - m.logger.LogWarn("Error stopping user during deletion", "bridge_type", m.bridgeType, "user_id", userID, "error", err) - } - - // Disconnect if still connected - if user.IsConnected() { - if err := user.Disconnect(); err != nil { - m.logger.LogWarn("Error disconnecting user during deletion", "bridge_type", m.bridgeType, "user_id", userID, "error", err) - } - } - - // Remove from map - delete(m.users, userID) - - m.logger.LogInfo("Bridge user deleted successfully", "bridge_type", m.bridgeType, "user_id", userID) - return nil -} - -// ListUsers returns a list of all users -func (m *UserManager) ListUsers() []model.BridgeUser { - m.mu.RLock() - defer m.mu.RUnlock() - - users := make([]model.BridgeUser, 0, len(m.users)) - for _, user := range m.users { - users = append(users, user) - } - - return users -} - -// HasUser checks if a user exists -func (m *UserManager) HasUser(userID string) bool { - m.mu.RLock() - defer m.mu.RUnlock() - - _, exists := m.users[userID] - return exists -} - -// Start initializes the user manager -func (m *UserManager) Start(ctx context.Context) error { - m.logger.LogDebug("Starting user manager", "bridge_type", m.bridgeType) - - // Update context - m.ctx = ctx - - // Start all existing users - m.mu.RLock() - defer m.mu.RUnlock() - - for userID, user := range m.users { - if err := user.Start(ctx); err != nil { - m.logger.LogWarn("Failed to start user during manager startup", "bridge_type", m.bridgeType, "user_id", userID, "error", err) - // Continue starting other users even if one fails - } - } - - m.logger.LogInfo("User manager started", "bridge_type", m.bridgeType, "user_count", len(m.users)) - return nil -} - -// Stop shuts down the user manager -func (m *UserManager) Stop() error { - m.logger.LogDebug("Stopping user manager", "bridge_type", m.bridgeType) - - if m.cancel != nil { - m.cancel() - } - - // Stop all users - m.mu.RLock() - users := make([]model.BridgeUser, 0, len(m.users)) - for _, user := range m.users { - users = append(users, user) - } - m.mu.RUnlock() - - for _, user := range users { - if err := user.Stop(); err != nil { - m.logger.LogWarn("Error stopping user during manager shutdown", "bridge_type", m.bridgeType, "user_id", user.GetID(), "error", err) - } - } - - m.logger.LogInfo("User manager stopped", "bridge_type", m.bridgeType) - return nil -} - -// UpdateConfiguration updates configuration for all users -func (m *UserManager) UpdateConfiguration(cfg *config.Configuration) error { - m.logger.LogDebug("Updating configuration for user manager", "bridge_type", m.bridgeType) - - // For now, we don't propagate config changes to individual users - // This can be extended later if needed - m.logger.LogInfo("User manager configuration updated", "bridge_type", m.bridgeType) - return nil -} - -// GetBridgeType returns the bridge type this manager handles -func (m *UserManager) GetBridgeType() string { - return m.bridgeType -} diff --git a/server/bridge/xmpp/bridge.go b/server/bridge/xmpp/bridge.go index 4a1ffe6..4c6392a 100644 --- a/server/bridge/xmpp/bridge.go +++ b/server/bridge/xmpp/bridge.go @@ -9,7 +9,6 @@ import ( "fmt" - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/bridge" "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/config" "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/logger" pluginModel "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/model" @@ -20,11 +19,10 @@ import ( // xmppBridge handles syncing messages between Mattermost and XMPP type xmppBridge struct { - logger logger.Logger - api plugin.API - kvstore kvstore.KVStore - bridgeClient *xmppClient.Client // Main bridge XMPP client connection - userManager pluginModel.BridgeUserManager + logger logger.Logger + api plugin.API + kvstore kvstore.KVStore + xmppClient *xmppClient.Client // Connection management connected atomic.Bool @@ -43,7 +41,7 @@ type xmppBridge struct { // NewBridge creates a new XMPP bridge func NewBridge(log logger.Logger, api plugin.API, kvstore kvstore.KVStore, cfg *config.Configuration) pluginModel.Bridge { ctx, cancel := context.WithCancel(context.Background()) - b := &xmppBridge{ + bridge := &xmppBridge{ logger: log, api: api, kvstore: kvstore, @@ -51,15 +49,14 @@ func NewBridge(log logger.Logger, api plugin.API, kvstore kvstore.KVStore, cfg * cancel: cancel, channelMappings: make(map[string]string), config: cfg, - userManager: bridge.NewUserManager("xmpp", log), } // Initialize XMPP client with configuration if cfg.EnableSync && cfg.XMPPServerURL != "" && cfg.XMPPUsername != "" && cfg.XMPPPassword != "" { - b.bridgeClient = b.createXMPPClient(cfg) + bridge.xmppClient = bridge.createXMPPClient(cfg) } - return b + return bridge } // createXMPPClient creates an XMPP client with the given configuration @@ -74,9 +71,8 @@ func (b *xmppBridge) createXMPPClient(cfg *config.Configuration) *xmppClient.Cli cfg.XMPPUsername, cfg.XMPPPassword, cfg.GetXMPPResource(), - "", // remoteID not needed for bridge client + "", // remoteID not needed for bridge user tlsConfig, - b.logger, ) } @@ -90,28 +86,28 @@ func (b *xmppBridge) UpdateConfiguration(newConfig any) error { b.configMu.Lock() oldConfig := b.config b.config = cfg - defer b.configMu.Unlock() - - b.logger.LogInfo("XMPP bridge configuration updated") // Initialize or update XMPP client with new configuration if cfg.EnableSync { if cfg.XMPPServerURL == "" || cfg.XMPPUsername == "" || cfg.XMPPPassword == "" { + b.configMu.Unlock() return fmt.Errorf("XMPP server URL, username, and password are required when sync is enabled") } - b.bridgeClient = b.createXMPPClient(cfg) + b.xmppClient = b.createXMPPClient(cfg) } else { - b.bridgeClient = nil + b.xmppClient = nil } + b.configMu.Unlock() + // Check if we need to restart the bridge due to configuration changes wasConnected := b.connected.Load() needsRestart := oldConfig != nil && !oldConfig.Equals(cfg) && wasConnected // Log the configuration change if needsRestart { - b.logger.LogInfo("Configuration changed, restarting bridge") + b.logger.LogInfo("Configuration changed, restarting bridge", "old_config", oldConfig, "new_config", cfg) } else { b.logger.LogInfo("Configuration updated", "config", cfg) } @@ -146,6 +142,9 @@ func (b *xmppBridge) Start() error { return fmt.Errorf("bridge configuration not set") } + // Print the configuration for debugging + b.logger.LogDebug("Bridge configuration", "config", config) + if !config.EnableSync { b.logger.LogInfo("XMPP sync is disabled, bridge will not start") return nil @@ -178,8 +177,8 @@ func (b *xmppBridge) Stop() error { b.cancel() } - if b.bridgeClient != nil { - if err := b.bridgeClient.Disconnect(); err != nil { + if b.xmppClient != nil { + if err := b.xmppClient.Disconnect(); err != nil { b.logger.LogWarn("Error disconnecting from XMPP server", "error", err) } } @@ -191,13 +190,13 @@ func (b *xmppBridge) Stop() error { // connectToXMPP establishes connection to the XMPP server func (b *xmppBridge) connectToXMPP() error { - if b.bridgeClient == nil { + if b.xmppClient == nil { return fmt.Errorf("XMPP client is not initialized") } b.logger.LogDebug("Connecting to XMPP server") - err := b.bridgeClient.Connect() + err := b.xmppClient.Connect() if err != nil { b.connected.Store(false) return fmt.Errorf("failed to connect to XMPP server: %w", err) @@ -207,11 +206,11 @@ func (b *xmppBridge) connectToXMPP() error { b.logger.LogInfo("Successfully connected to XMPP server") // Set online presence after successful connection - if err := b.bridgeClient.SetOnlinePresence(); err != nil { + if err := b.xmppClient.SetOnlinePresence(); err != nil { b.logger.LogWarn("Failed to set online presence", "error", err) // Don't fail the connection for presence issues } else { - b.logger.LogDebug("Set bridge client online presence") + b.logger.LogDebug("Set bridge user online presence") } return nil @@ -250,7 +249,7 @@ func (b *xmppBridge) joinXMPPRoom(channelID, roomJID string) error { return fmt.Errorf("not connected to XMPP server") } - err := b.bridgeClient.JoinRoom(roomJID) + err := b.xmppClient.JoinRoom(roomJID) if err != nil { return fmt.Errorf("failed to join XMPP room: %w", err) } @@ -312,7 +311,7 @@ func (b *xmppBridge) connectionMonitor() { case <-b.ctx.Done(): return case <-ticker.C: - if err := b.Ping(); err != nil { + if err := b.checkConnection(); err != nil { b.logger.LogWarn("XMPP connection check failed", "error", err) b.handleReconnection() } @@ -320,6 +319,14 @@ func (b *xmppBridge) connectionMonitor() { } } +// checkConnection verifies the XMPP connection is still active +func (b *xmppBridge) checkConnection() error { + if !b.connected.Load() { + return fmt.Errorf("not connected") + } + return b.xmppClient.TestConnection() +} + // handleReconnection attempts to reconnect to XMPP and rejoin rooms func (b *xmppBridge) handleReconnection() { b.configMu.RLock() @@ -333,8 +340,8 @@ func (b *xmppBridge) handleReconnection() { b.logger.LogInfo("Attempting to reconnect to XMPP server") b.connected.Store(false) - if b.bridgeClient != nil { - _ = b.bridgeClient.Disconnect() + if b.xmppClient != nil { + b.xmppClient.Disconnect() } // Retry connection with exponential backoff @@ -371,35 +378,19 @@ func (b *xmppBridge) IsConnected() bool { return b.connected.Load() } -// Ping actively tests the XMPP connection health -func (b *xmppBridge) Ping() error { - if !b.connected.Load() { - return fmt.Errorf("XMPP bridge is not connected") - } - - if b.bridgeClient == nil { - return fmt.Errorf("XMPP client not initialized") - } - - b.logger.LogDebug("Testing XMPP bridge connectivity with ping") - - // Use the XMPP client's ping method - if err := b.bridgeClient.Ping(); err != nil { - b.logger.LogWarn("XMPP bridge ping failed", "error", err) - return fmt.Errorf("XMPP bridge ping failed: %w", err) - } - - b.logger.LogDebug("XMPP bridge ping successful") - return nil -} - -// CreateChannelMapping creates a mapping between a Mattermost channel and XMPP room -func (b *xmppBridge) CreateChannelMapping(channelID, roomJID string) error { +// CreateChannelRoomMapping creates a mapping between a Mattermost channel and XMPP room +func (b *xmppBridge) CreateChannelRoomMapping(channelID, roomJID string) error { if b.kvstore == nil { return fmt.Errorf("KV store not initialized") } - err := b.kvstore.Set(kvstore.BuildChannelMapKey("xmpp", roomJID), []byte(channelID)) + // Store forward and reverse mappings using bridge-agnostic keys + err := b.kvstore.Set(kvstore.BuildChannelMapKey("mattermost", channelID), []byte(roomJID)) + if err != nil { + return fmt.Errorf("failed to store channel room mapping: %w", err) + } + + err = b.kvstore.Set(kvstore.BuildChannelMapKey("xmpp", roomJID), []byte(channelID)) if err != nil { return fmt.Errorf("failed to store reverse room mapping: %w", err) } @@ -411,7 +402,7 @@ func (b *xmppBridge) CreateChannelMapping(channelID, roomJID string) error { // Join the room if connected if b.connected.Load() { - if err := b.bridgeClient.JoinRoom(roomJID); err != nil { + if err := b.xmppClient.JoinRoom(roomJID); err != nil { b.logger.LogWarn("Failed to join newly mapped room", "channel_id", channelID, "room_jid", roomJID, "error", err) } } @@ -420,8 +411,8 @@ func (b *xmppBridge) CreateChannelMapping(channelID, roomJID string) error { return nil } -// GetChannelMapping gets the XMPP room JID for a Mattermost channel -func (b *xmppBridge) GetChannelMapping(channelID string) (string, error) { +// GetChannelRoomMapping gets the XMPP room JID for a Mattermost channel +func (b *xmppBridge) GetChannelRoomMapping(channelID string) (string, error) { // Check cache first b.mappingsMu.RLock() roomJID, exists := b.channelMappings[channelID] @@ -436,7 +427,7 @@ func (b *xmppBridge) GetChannelMapping(channelID string) (string, error) { } // Check if we have a mapping in the KV store for this channel ID - roomJIDBytes, err := b.kvstore.Get(kvstore.BuildChannelMapKey("xmpp", channelID)) + roomJIDBytes, err := b.kvstore.Get(kvstore.BuildChannelMapKey("mattermost", channelID)) if err != nil { return "", nil // Unmapped channels are expected } @@ -450,92 +441,3 @@ func (b *xmppBridge) GetChannelMapping(channelID string) (string, error) { return roomJID, nil } - -// DeleteChannelMapping removes a mapping between a Mattermost channel and XMPP room -func (b *xmppBridge) DeleteChannelMapping(channelID string) error { - if b.kvstore == nil { - return fmt.Errorf("KV store not initialized") - } - - // Get the room JID from the mapping before deleting - roomJID, err := b.GetChannelMapping(channelID) - if err != nil { - return fmt.Errorf("failed to get channel mapping: %w", err) - } - if roomJID == "" { - return fmt.Errorf("channel is not mapped to any room") - } - - err = b.kvstore.Delete(kvstore.BuildChannelMapKey("xmpp", roomJID)) - if err != nil { - return fmt.Errorf("failed to delete reverse room mapping: %w", err) - } - - // Remove from local cache - b.mappingsMu.Lock() - delete(b.channelMappings, channelID) - b.mappingsMu.Unlock() - - // Leave the room if connected - if b.connected.Load() && b.bridgeClient != nil { - if err := b.bridgeClient.LeaveRoom(roomJID); err != nil { - b.logger.LogWarn("Failed to leave unmapped room", "channel_id", channelID, "room_jid", roomJID, "error", err) - // Don't fail the entire operation if leaving the room fails - } else { - b.logger.LogInfo("Left XMPP room after unmapping", "channel_id", channelID, "room_jid", roomJID) - } - } - - b.logger.LogInfo("Deleted channel room mapping", "channel_id", channelID, "room_jid", roomJID) - return nil -} - -// RoomExists checks if an XMPP room exists on the remote service -func (b *xmppBridge) RoomExists(roomID string) (bool, error) { - if !b.connected.Load() { - return false, fmt.Errorf("not connected to XMPP server") - } - - if b.bridgeClient == nil { - return false, fmt.Errorf("XMPP client not initialized") - } - - b.logger.LogDebug("Checking if XMPP room exists", "room_jid", roomID) - - // Use the XMPP client to check room existence - exists, err := b.bridgeClient.CheckRoomExists(roomID) - if err != nil { - b.logger.LogError("Failed to check room existence", "room_jid", roomID, "error", err) - return false, fmt.Errorf("failed to check room existence: %w", err) - } - - b.logger.LogDebug("Room existence check completed", "room_jid", roomID, "exists", exists) - return exists, nil -} - -// GetRoomMapping retrieves the Mattermost channel ID for a given XMPP room JID (reverse lookup) -func (b *xmppBridge) GetRoomMapping(roomID string) (string, error) { - if b.kvstore == nil { - return "", fmt.Errorf("KV store not initialized") - } - - b.logger.LogDebug("Getting channel mapping for XMPP room", "room_jid", roomID) - - // Look up the channel ID using the room JID as the key - channelIDBytes, err := b.kvstore.Get(kvstore.BuildChannelMapKey("xmpp", roomID)) - if err != nil { - // No mapping found is not an error, just return empty string - b.logger.LogDebug("No channel mapping found for room", "room_jid", roomID) - return "", nil - } - - channelID := string(channelIDBytes) - b.logger.LogDebug("Found channel mapping for room", "room_jid", roomID, "channel_id", channelID) - - return channelID, nil -} - -// GetUserManager returns the user manager for this bridge -func (b *xmppBridge) GetUserManager() pluginModel.BridgeUserManager { - return b.userManager -} diff --git a/server/bridge/xmpp/user.go b/server/bridge/xmpp/user.go deleted file mode 100644 index fd03afa..0000000 --- a/server/bridge/xmpp/user.go +++ /dev/null @@ -1,336 +0,0 @@ -package xmpp - -import ( - "context" - "crypto/tls" - "fmt" - "sync" - "sync/atomic" - "time" - - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/config" - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/logger" - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/model" - xmppClient "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/xmpp" -) - -// XMPPUser represents an XMPP user that implements the BridgeUser interface -type XMPPUser struct { - // User identity - id string - displayName string - jid string - - // XMPP client - client *xmppClient.Client - - // State management - state model.UserState - stateMu sync.RWMutex - connected atomic.Bool - - // Configuration - config *config.Configuration - - // Goroutine lifecycle - ctx context.Context - cancel context.CancelFunc - - // Logger - logger logger.Logger -} - -// NewXMPPUser creates a new XMPP user -func NewXMPPUser(id, displayName, jid string, cfg *config.Configuration, logger logger.Logger) *XMPPUser { - ctx, cancel := context.WithCancel(context.Background()) - - // Create TLS config based on certificate verification setting - tlsConfig := &tls.Config{ - InsecureSkipVerify: cfg.XMPPInsecureSkipVerify, - } - - // Create XMPP client for this user - client := xmppClient.NewClientWithTLS( - cfg.XMPPServerURL, - jid, - cfg.XMPPPassword, // This might need to be user-specific in the future - cfg.GetXMPPResource(), - id, // Use user ID as remote ID - tlsConfig, - logger, - ) - - return &XMPPUser{ - id: id, - displayName: displayName, - jid: jid, - client: client, - state: model.UserStateOffline, - config: cfg, - ctx: ctx, - cancel: cancel, - logger: logger, - } -} - -// Validation -func (u *XMPPUser) Validate() error { - if u.id == "" { - return fmt.Errorf("user ID cannot be empty") - } - if u.jid == "" { - return fmt.Errorf("JID cannot be empty") - } - if u.config == nil { - return fmt.Errorf("configuration cannot be nil") - } - if u.config.XMPPServerURL == "" { - return fmt.Errorf("XMPP server URL cannot be empty") - } - if u.client == nil { - return fmt.Errorf("XMPP client cannot be nil") - } - return nil -} - -// Identity (bridge-agnostic) -func (u *XMPPUser) GetID() string { - return u.id -} - -func (u *XMPPUser) GetDisplayName() string { - return u.displayName -} - -// State management -func (u *XMPPUser) GetState() model.UserState { - u.stateMu.RLock() - defer u.stateMu.RUnlock() - return u.state -} - -func (u *XMPPUser) SetState(state model.UserState) error { - u.stateMu.Lock() - defer u.stateMu.Unlock() - - u.logger.LogDebug("Changing XMPP user state", "user_id", u.id, "old_state", u.state, "new_state", state) - u.state = state - - // TODO: Send presence update to XMPP server based on state - // This would involve mapping UserState to XMPP presence types - - return nil -} - -// Channel operations -func (u *XMPPUser) JoinChannel(channelID string) error { - if !u.connected.Load() { - return fmt.Errorf("user %s is not connected", u.id) - } - - u.logger.LogDebug("XMPP user joining channel", "user_id", u.id, "channel_id", channelID) - - // For XMPP, channelID is the room JID - err := u.client.JoinRoom(channelID) - if err != nil { - return fmt.Errorf("failed to join XMPP room %s: %w", channelID, err) - } - - u.logger.LogInfo("XMPP user joined channel", "user_id", u.id, "channel_id", channelID) - return nil -} - -func (u *XMPPUser) LeaveChannel(channelID string) error { - if !u.connected.Load() { - return fmt.Errorf("user %s is not connected", u.id) - } - - u.logger.LogDebug("XMPP user leaving channel", "user_id", u.id, "channel_id", channelID) - - // For XMPP, channelID is the room JID - err := u.client.LeaveRoom(channelID) - if err != nil { - return fmt.Errorf("failed to leave XMPP room %s: %w", channelID, err) - } - - u.logger.LogInfo("XMPP user left channel", "user_id", u.id, "channel_id", channelID) - return nil -} - -func (u *XMPPUser) SendMessageToChannel(channelID, message string) error { - if !u.connected.Load() { - return fmt.Errorf("user %s is not connected", u.id) - } - - u.logger.LogDebug("XMPP user sending message to channel", "user_id", u.id, "channel_id", channelID) - - // Create message request for XMPP - req := xmppClient.MessageRequest{ - RoomJID: channelID, - GhostUserJID: u.jid, - Message: message, - } - - _, err := u.client.SendMessage(req) - if err != nil { - return fmt.Errorf("failed to send message to XMPP room %s: %w", channelID, err) - } - - u.logger.LogDebug("XMPP user sent message to channel", "user_id", u.id, "channel_id", channelID) - return nil -} - -// Connection lifecycle -func (u *XMPPUser) Connect() error { - u.logger.LogDebug("Connecting XMPP user", "user_id", u.id, "jid", u.jid) - - err := u.client.Connect() - if err != nil { - u.connected.Store(false) - return fmt.Errorf("failed to connect XMPP user %s: %w", u.id, err) - } - - u.connected.Store(true) - u.logger.LogInfo("XMPP user connected", "user_id", u.id, "jid", u.jid) - - // Set online presence after successful connection - if err := u.client.SetOnlinePresence(); err != nil { - u.logger.LogWarn("Failed to set online presence for XMPP user", "user_id", u.id, "error", err) - // Don't fail the connection for presence issues - } - - // Update state to online - _ = u.SetState(model.UserStateOnline) - - return nil -} - -func (u *XMPPUser) Disconnect() error { - u.logger.LogDebug("Disconnecting XMPP user", "user_id", u.id, "jid", u.jid) - - if u.client == nil { - return nil - } - - err := u.client.Disconnect() - if err != nil { - u.logger.LogWarn("Error disconnecting XMPP user", "user_id", u.id, "error", err) - } - - u.connected.Store(false) - _ = u.SetState(model.UserStateOffline) - - u.logger.LogInfo("XMPP user disconnected", "user_id", u.id, "jid", u.jid) - return err -} - -func (u *XMPPUser) IsConnected() bool { - return u.connected.Load() -} - -func (u *XMPPUser) Ping() error { - if !u.connected.Load() { - return fmt.Errorf("XMPP user %s is not connected", u.id) - } - - if u.client == nil { - return fmt.Errorf("XMPP client not initialized for user %s", u.id) - } - - return u.client.Ping() -} - -// CheckChannelExists checks if an XMPP room/channel exists -func (u *XMPPUser) CheckChannelExists(channelID string) (bool, error) { - if !u.connected.Load() { - return false, fmt.Errorf("XMPP user %s is not connected", u.id) - } - - if u.client == nil { - return false, fmt.Errorf("XMPP client not initialized for user %s", u.id) - } - - return u.client.CheckRoomExists(channelID) -} - -// Goroutine lifecycle -func (u *XMPPUser) Start(ctx context.Context) error { - u.logger.LogDebug("Starting XMPP user", "user_id", u.id, "jid", u.jid) - - // Update context - u.ctx = ctx - - // Connect to XMPP server - if err := u.Connect(); err != nil { - return fmt.Errorf("failed to start XMPP user %s: %w", u.id, err) - } - - // Start connection monitoring in a goroutine - go u.connectionMonitor() - - u.logger.LogInfo("XMPP user started", "user_id", u.id, "jid", u.jid) - return nil -} - -func (u *XMPPUser) Stop() error { - u.logger.LogDebug("Stopping XMPP user", "user_id", u.id, "jid", u.jid) - - // Cancel context to stop goroutines - if u.cancel != nil { - u.cancel() - } - - // Disconnect from XMPP server - if err := u.Disconnect(); err != nil { - u.logger.LogWarn("Error disconnecting XMPP user during stop", "user_id", u.id, "error", err) - } - - u.logger.LogInfo("XMPP user stopped", "user_id", u.id, "jid", u.jid) - return nil -} - -// connectionMonitor monitors the XMPP connection for this user -func (u *XMPPUser) connectionMonitor() { - u.logger.LogDebug("Starting connection monitor for XMPP user", "user_id", u.id) - - // Simple monitoring - check connection periodically - for { - select { - case <-u.ctx.Done(): - u.logger.LogDebug("Connection monitor stopped for XMPP user", "user_id", u.id) - return - default: - // Check connection every 30 seconds - if u.connected.Load() { - if err := u.client.Ping(); err != nil { - u.logger.LogWarn("Connection check failed for XMPP user", "user_id", u.id, "error", err) - u.connected.Store(false) - _ = u.SetState(model.UserStateOffline) - - // TODO: Implement reconnection logic if needed - } - } - - // Wait before next check - timeoutCtx, cancel := context.WithTimeout(u.ctx, 30*time.Second) // 30 seconds - select { - case <-u.ctx.Done(): - cancel() - return - case <-timeoutCtx.Done(): - cancel() - continue - } - } - } -} - -// GetJID returns the XMPP JID for this user (XMPP-specific method) -func (u *XMPPUser) GetJID() string { - return u.jid -} - -// GetClient returns the underlying XMPP client (for advanced operations) -func (u *XMPPUser) GetClient() *xmppClient.Client { - return u.client -} diff --git a/server/command/command.go b/server/command/command.go index d15b9f5..1feed2d 100644 --- a/server/command/command.go +++ b/server/command/command.go @@ -29,9 +29,6 @@ func NewCommandHandler(client *pluginapi.Client, bridgeManager pluginModel.Bridg mapSubcommand.AddTextArgument("XMPP room JID (e.g., room@conference.example.com)", "[room_jid]", "") xmppBridgeData.AddCommand(mapSubcommand) - unmapSubcommand := model.NewAutocompleteData("unmap", "", "Unmap current channel from XMPP room") - xmppBridgeData.AddCommand(unmapSubcommand) - statusSubcommand := model.NewAutocompleteData("status", "", "Show bridge connection status") xmppBridgeData.AddCommand(statusSubcommand) @@ -39,7 +36,7 @@ func NewCommandHandler(client *pluginapi.Client, bridgeManager pluginModel.Bridg Trigger: xmppBridgeCommandTrigger, AutoComplete: true, AutoCompleteDesc: "Manage XMPP bridge mappings", - AutoCompleteHint: "[map|unmap|status]", + AutoCompleteHint: "[map|status]", AutocompleteData: xmppBridgeData, }) if err != nil { @@ -54,14 +51,6 @@ func NewCommandHandler(client *pluginapi.Client, bridgeManager pluginModel.Bridg // ExecuteCommand hook calls this method to execute the commands that were registered in the NewCommandHandler function. func (c *Handler) Handle(args *model.CommandArgs) (*model.CommandResponse, error) { - // Check if user is system admin for all plugin commands - if !c.isSystemAdmin(args.UserId) { - return &model.CommandResponse{ - ResponseType: model.CommandResponseTypeEphemeral, - Text: "❌ Only system administrators can use XMPP bridge commands.", - }, nil - } - trigger := strings.TrimPrefix(strings.Fields(args.Command)[0], "/") switch trigger { case xmppBridgeCommandTrigger: @@ -83,7 +72,6 @@ func (c *Handler) executeXMPPBridgeCommand(args *model.CommandArgs) *model.Comma **Available commands:** - ` + "`/xmppbridge map `" + ` - Map current channel to XMPP room -- ` + "`/xmppbridge unmap`" + ` - Unmap current channel from XMPP room - ` + "`/xmppbridge status`" + ` - Show bridge connection status **Example:** @@ -95,8 +83,6 @@ func (c *Handler) executeXMPPBridgeCommand(args *model.CommandArgs) *model.Comma switch subcommand { case "map": return c.executeMapCommand(args, fields) - case "unmap": - return c.executeUnmapCommand(args) case "status": return c.executeStatusCommand(args) default: @@ -126,7 +112,7 @@ func (c *Handler) executeMapCommand(args *model.CommandArgs, fields []string) *m } } - // Get the XMPP bridge to check existing mappings + // Get the XMPP bridge bridge, err := c.bridgeManager.GetBridge("xmpp") if err != nil { return &model.CommandResponse{ @@ -144,7 +130,7 @@ func (c *Handler) executeMapCommand(args *model.CommandArgs, fields []string) *m } // Check if channel is already mapped - existingMapping, err := bridge.GetChannelMapping(channelID) + existingMapping, err := bridge.GetChannelRoomMapping(channelID) if err != nil { return &model.CommandResponse{ ResponseType: model.CommandResponseTypeEphemeral, @@ -159,73 +145,21 @@ func (c *Handler) executeMapCommand(args *model.CommandArgs, fields []string) *m } } - // Create the mapping using BridgeManager - mappingReq := pluginModel.CreateChannelMappingRequest{ - ChannelID: channelID, - BridgeName: "xmpp", - BridgeRoomID: roomJID, - UserID: args.UserId, - TeamID: args.TeamId, - } - - err = c.bridgeManager.CreateChannelMapping(mappingReq) + // Create the mapping + err = bridge.CreateChannelRoomMapping(channelID, roomJID) if err != nil { - return c.formatMappingError("create", roomJID, err) + return &model.CommandResponse{ + ResponseType: model.CommandResponseTypeEphemeral, + Text: fmt.Sprintf("❌ Failed to create channel mapping: %v", err), + } } return &model.CommandResponse{ - ResponseType: model.CommandResponseTypeEphemeral, + ResponseType: model.CommandResponseTypeInChannel, Text: fmt.Sprintf("✅ Successfully mapped this channel to XMPP room: `%s`", roomJID), } } -func (c *Handler) executeUnmapCommand(args *model.CommandArgs) *model.CommandResponse { - channelID := args.ChannelId - - // Get the XMPP bridge to check existing mappings - bridge, err := c.bridgeManager.GetBridge("xmpp") - if err != nil { - return &model.CommandResponse{ - ResponseType: model.CommandResponseTypeEphemeral, - Text: "❌ XMPP bridge is not available. Please check the plugin configuration.", - } - } - - // Check if channel is mapped - roomJID, err := bridge.GetChannelMapping(channelID) - if err != nil { - return &model.CommandResponse{ - ResponseType: model.CommandResponseTypeEphemeral, - Text: fmt.Sprintf("Error checking existing mapping: %v", err), - } - } - - if roomJID == "" { - return &model.CommandResponse{ - ResponseType: model.CommandResponseTypeEphemeral, - Text: "❌ This channel is not mapped to any XMPP room.", - } - } - - // Delete the mapping - deleteReq := pluginModel.DeleteChannelMappingRequest{ - ChannelID: channelID, - BridgeName: "xmpp", - UserID: args.UserId, - TeamID: args.TeamId, - } - - err = c.bridgeManager.DeleteChannepMapping(deleteReq) - if err != nil { - return c.formatMappingError("delete", roomJID, err) - } - - return &model.CommandResponse{ - ResponseType: model.CommandResponseTypeEphemeral, - Text: fmt.Sprintf("✅ Successfully unmapped this channel from XMPP room: `%s`", roomJID), - } -} - func (c *Handler) executeStatusCommand(args *model.CommandArgs) *model.CommandResponse { // Get the XMPP bridge bridge, err := c.bridgeManager.GetBridge("xmpp") @@ -247,7 +181,7 @@ func (c *Handler) executeStatusCommand(args *model.CommandArgs) *model.CommandRe // Check if current channel is mapped channelID := args.ChannelId - roomJID, err := bridge.GetChannelMapping(channelID) + roomJID, err := bridge.GetChannelRoomMapping(channelID) var mappingText string if err != nil { @@ -267,89 +201,6 @@ func (c *Handler) executeStatusCommand(args *model.CommandArgs) *model.CommandRe %s **Commands:** -- Use `+"`/xmppbridge map `"+` to map this channel to an XMPP room -- Use `+"`/xmppbridge unmap`"+` to unmap this channel from an XMPP room`, statusText, mappingText), - } -} - -// isSystemAdmin checks if the user is a system administrator -func (c *Handler) isSystemAdmin(userID string) bool { - user, err := c.client.User.Get(userID) - if err != nil { - c.client.Log.Warn("Failed to get user for admin check", "user_id", userID, "error", err) - return false - } - - return user.IsSystemAdmin() -} - -// formatMappingError provides user-friendly error messages for mapping operations -func (c *Handler) formatMappingError(operation, roomJID string, err error) *model.CommandResponse { - errorMsg := err.Error() - - // Handle specific error cases with user-friendly messages - switch { - case strings.Contains(errorMsg, "already mapped to channel"): - return &model.CommandResponse{ - ResponseType: model.CommandResponseTypeEphemeral, - Text: fmt.Sprintf(`❌ **Room Already Mapped** - -The XMPP room **%s** is already connected to another channel. - -**What you can do:** -- Choose a different XMPP room that isn't already in use -- Unmap the room from the other channel first using `+"`/xmppbridge unmap`"+` -- Use `+"`/xmppbridge status`"+` to check current mappings`, roomJID), - } - - case strings.Contains(errorMsg, "does not exist"): - return &model.CommandResponse{ - ResponseType: model.CommandResponseTypeEphemeral, - Text: fmt.Sprintf(`❌ **Room Not Found** - -The XMPP room **%s** doesn't exist or isn't accessible. - -**What you can do:** -- Check that the room JID is spelled correctly -- Make sure the room exists on the XMPP server -- Verify you have permission to access the room -- Contact your XMPP administrator if needed - -**Example format:** room@conference.example.com`, roomJID), - } - - case strings.Contains(errorMsg, "not connected"): - return &model.CommandResponse{ - ResponseType: model.CommandResponseTypeEphemeral, - Text: `❌ **Bridge Not Connected** - -The XMPP bridge is currently disconnected. - -**What you can do:** -- Wait a moment and try again (the bridge may be reconnecting) -- Contact your system administrator -- Use ` + "`/xmppbridge status`" + ` to check the connection status`, - } - - default: - // Generic error message for unknown cases - action := "create the mapping" - if operation == "delete" { - action = "remove the mapping" - } - - return &model.CommandResponse{ - ResponseType: model.CommandResponseTypeEphemeral, - Text: fmt.Sprintf(`❌ **Operation Failed** - -Unable to %s for room **%s**. - -**What you can do:** -- Try the command again in a few moments -- Use `+"`/xmppbridge status`"+` to check the bridge status -- Contact your system administrator if the problem persists - -**Error details:** %s`, action, roomJID, errorMsg), - } +- Use `+"`/xmppbridge map `"+` to map this channel to an XMPP room`, statusText, mappingText), } } diff --git a/server/config/config.go b/server/config/config.go index db8c497..824d2bc 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -19,13 +19,13 @@ const DefaultXMPPUsernamePrefix = "xmpp" // If you add non-reference types to your configuration struct, be sure to rewrite Clone as a deep // copy appropriate for your types. type Configuration struct { - XMPPServerURL string `json:"XMPPServerURL"` - XMPPUsername string `json:"XMPPUsername"` - XMPPPassword string `json:"XMPPPassword"` - EnableSync bool `json:"EnableSync"` - XMPPUsernamePrefix string `json:"XMPPUsernamePrefix"` - XMPPResource string `json:"XMPPResource"` - XMPPInsecureSkipVerify bool `json:"XMPPInsecureSkipVerify"` + XMPPServerURL string `json:"XMPPServerURL"` + XMPPUsername string `json:"XMPPUsername"` + XMPPPassword string `json:"XMPPPassword"` + EnableSync bool `json:"EnableSync"` + XMPPUsernamePrefix string `json:"XMPPUsernamePrefix"` + XMPPResource string `json:"XMPPResource"` + XMPPInsecureSkipVerify bool `json:"XMPPInsecureSkipVerify"` } // Equals compares two configuration structs @@ -95,4 +95,4 @@ func (c *Configuration) IsValid() error { } return nil -} +} \ No newline at end of file diff --git a/server/hooks_sharedchannels.go b/server/hooks_sharedchannels.go deleted file mode 100644 index 798ba0f..0000000 --- a/server/hooks_sharedchannels.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import "github.com/mattermost/mattermost/server/public/model" - -// OnSharedChannelsPing is called to check if the bridge is healthy and ready to process messages -func (p *Plugin) OnSharedChannelsPing(remoteCluster *model.RemoteCluster) bool { - config := p.getConfiguration() - - p.logger.LogDebug("OnSharedChannelsPing called", "remote_cluster_id", remoteCluster.RemoteId) - - var remoteClusterID string - if remoteCluster != nil { - remoteClusterID = remoteCluster.RemoteId - } - - p.logger.LogDebug("Received shared channels ping", "remote_cluster_id", remoteClusterID) - - // If sync is disabled, we're still "healthy" but not actively processing - if !config.EnableSync { - p.logger.LogDebug("Ping received but sync is disabled", "remote_cluster_id", remoteClusterID) - return true - } - - // Check if bridge manager is available - if p.bridgeManager == nil { - p.logger.LogError("Bridge manager not initialized during ping", "remote_cluster_id", remoteClusterID) - return false - } - - // Get the XMPP bridge for active connectivity testing - bridge, err := p.bridgeManager.GetBridge("xmpp") - if err != nil { - p.logger.LogWarn("XMPP bridge not available during ping", "error", err, "remote_cluster_id", remoteClusterID) - // Return true if bridge is not registered - this might be expected during startup/shutdown - return false - } - - // Perform active ping test on the XMPP bridge - if err := bridge.Ping(); err != nil { - p.logger.LogError("XMPP bridge ping failed", "error", err, "remote_cluster_id", remoteClusterID) - return false - } - - p.logger.LogDebug("Shared channels ping successful - XMPP bridge is healthy", "remote_cluster_id", remoteClusterID) - return true -} diff --git a/server/logger/logger.go b/server/logger/logger.go index 9b5b9dc..25b4743 100644 --- a/server/logger/logger.go +++ b/server/logger/logger.go @@ -38,4 +38,4 @@ func (l *PluginAPILogger) LogWarn(message string, keyValuePairs ...any) { // LogError logs an error message func (l *PluginAPILogger) LogError(message string, keyValuePairs ...any) { l.api.LogError(message, keyValuePairs...) -} +} \ No newline at end of file diff --git a/server/model/bridge.go b/server/model/bridge.go index bd00672..c9c7a3d 100644 --- a/server/model/bridge.go +++ b/server/model/bridge.go @@ -1,77 +1,5 @@ package model -import ( - "context" - "fmt" - - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/config" -) - -type BridgeID string - -type UserState int - -const ( - UserStateOnline UserState = iota - UserStateAway - UserStateBusy - UserStateOffline -) - -// CreateChannelMappingRequest contains information needed to create a channel mapping -type CreateChannelMappingRequest struct { - ChannelID string // Mattermost channel ID - BridgeName string // Name of the bridge (e.g., "xmpp") - BridgeRoomID string // Remote room/channel ID (e.g., JID for XMPP) - UserID string // ID of user who triggered the mapping creation - TeamID string // Team ID where the channel belongs -} - -// Validate checks if all required fields are present and valid -func (r CreateChannelMappingRequest) Validate() error { - if r.ChannelID == "" { - return fmt.Errorf("channelID cannot be empty") - } - if r.BridgeName == "" { - return fmt.Errorf("bridgeName cannot be empty") - } - if r.BridgeRoomID == "" { - return fmt.Errorf("bridgeRoomID cannot be empty") - } - if r.UserID == "" { - return fmt.Errorf("userID cannot be empty") - } - if r.TeamID == "" { - return fmt.Errorf("teamID cannot be empty") - } - return nil -} - -// DeleteChannelMappingRequest contains information needed to delete a channel mapping -type DeleteChannelMappingRequest struct { - ChannelID string // Mattermost channel ID - BridgeName string // Name of the bridge (e.g., "xmpp") - UserID string // ID of user who triggered the mapping deletion - TeamID string // Team ID where the channel belongs -} - -// Validate checks if all required fields are present and valid -func (r DeleteChannelMappingRequest) Validate() error { - if r.ChannelID == "" { - return fmt.Errorf("channelID cannot be empty") - } - if r.BridgeName == "" { - return fmt.Errorf("bridgeName cannot be empty") - } - if r.UserID == "" { - return fmt.Errorf("userID cannot be empty") - } - if r.TeamID == "" { - return fmt.Errorf("teamID cannot be empty") - } - return nil -} - type BridgeManager interface { // RegisterBridge registers a bridge with the given name. Returns an error if the name is empty, // the bridge is nil, or a bridge with the same name is already registered. @@ -111,12 +39,6 @@ type BridgeManager interface { // Returns an error if any bridge fails to update its configuration, but continues to // attempt updating all bridges. OnPluginConfigurationChange(config any) error - - // CreateChannelMapping is called when a channel mapping is created. - CreateChannelMapping(req CreateChannelMappingRequest) error - - // DeleteChannepMapping is called when a channel mapping is deleted. - DeleteChannepMapping(req DeleteChannelMappingRequest) error } type Bridge interface { @@ -129,79 +51,12 @@ type Bridge interface { // Stop stops the bridge Stop() error - // CreateChannelMapping creates a mapping between a Mattermost channel ID and an bridge room ID. - CreateChannelMapping(channelID, roomJID string) error + // CreateChannelRoomMapping creates a mapping between a Mattermost channel ID and an bridge room ID. + CreateChannelRoomMapping(channelID, roomJID string) error - // GetChannelMapping retrieves the bridge room ID for a given Mattermost channel ID. - GetChannelMapping(channelID string) (string, error) - - // DeleteChannelMapping removes a mapping between a Mattermost channel ID and a bridge room ID. - DeleteChannelMapping(channelID string) error - - // RoomExists checks if a room/channel exists on the remote service. - RoomExists(roomID string) (bool, error) - - // GetRoomMapping retrieves the Mattermost channel ID for a given room ID (reverse lookup). - GetRoomMapping(roomID string) (string, error) + // GetChannelRoomMapping retrieves the bridge room ID for a given Mattermost channel ID. + GetChannelRoomMapping(channelID string) (string, error) // IsConnected checks if the bridge is connected to the remote service. IsConnected() bool - - // Ping actively tests the bridge connection health by sending a lightweight request. - Ping() error - - // GetUserManager returns the user manager for this bridge. - GetUserManager() BridgeUserManager -} - -// BridgeUser represents a user connected to any bridge service -type BridgeUser interface { - // Validation - Validate() error - - // Identity (bridge-agnostic) - GetID() string - GetDisplayName() string - - // State management - GetState() UserState - SetState(state UserState) error - - // Channel operations (abstracted from rooms/channels/groups) - JoinChannel(channelID string) error - LeaveChannel(channelID string) error - SendMessageToChannel(channelID, message string) error - - // Connection lifecycle - Connect() error - Disconnect() error - IsConnected() bool - Ping() error - - // Channel existence check - CheckChannelExists(channelID string) (bool, error) - - // Goroutine lifecycle - Start(ctx context.Context) error - Stop() error -} - -// BridgeUserManager manages users for a specific bridge -type BridgeUserManager interface { - // User lifecycle - CreateUser(user BridgeUser) error - GetUser(userID string) (BridgeUser, error) - DeleteUser(userID string) error - ListUsers() []BridgeUser - HasUser(userID string) bool - - // Manager lifecycle - Start(ctx context.Context) error - Stop() error - - // Configuration updates - UpdateConfiguration(config *config.Configuration) error - - // Bridge type identification - GetBridgeType() string } diff --git a/server/model/strings.go b/server/model/strings.go deleted file mode 100644 index 1e559d9..0000000 --- a/server/model/strings.go +++ /dev/null @@ -1,40 +0,0 @@ -package model - -import "strings" - -// sanitizeShareName creates a valid ShareName matching the regex: ^[a-z0-9]+([a-z\-\_0-9]+|(__)?)[a-z0-9]*$ -func SanitizeShareName(name string) string { - // Convert to lowercase and replace spaces with hyphens - shareName := strings.ToLower(name) - shareName = strings.ReplaceAll(shareName, " ", "-") - - // Remove any characters that aren't lowercase letters, numbers, hyphens, or underscores - var validShareName strings.Builder - for _, r := range shareName { - if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' || r == '_' { - validShareName.WriteRune(r) - } - } - - result := validShareName.String() - if result == "" { - return "matrixbridge" // fallback if no valid characters - } - - // Ensure it starts with alphanumeric - for len(result) > 0 && (result[0] == '-' || result[0] == '_') { - result = result[1:] - } - - // Ensure it ends with alphanumeric - for len(result) > 0 && (result[len(result)-1] == '-' || result[len(result)-1] == '_') { - result = result[:len(result)-1] - } - - // Final fallback check - if result == "" { - return "matrixbridge" - } - - return result -} diff --git a/server/plugin.go b/server/plugin.go index f7a5f81..216dab4 100644 --- a/server/plugin.go +++ b/server/plugin.go @@ -7,7 +7,6 @@ import ( "time" "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/bridge" - mattermostbridge "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/bridge/mattermost" xmppbridge "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/bridge/xmpp" "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/command" "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/config" @@ -44,10 +43,6 @@ type Plugin struct { // remoteID is the identifier returned by RegisterPluginForSharedChannels remoteID string - // botUserID is the ID of the bot user created for this plugin - botUserID string - - // backgroundJob is the scheduled job that runs periodically to perform background tasks. backgroundJob *cluster.Job // configurationLock synchronizes access to the configuration. @@ -76,14 +71,8 @@ func (p *Plugin) OnActivate() error { cfg := p.getConfiguration() p.logger.LogDebug("Loaded configuration in OnActivate", "config", cfg) - // Register the plugin for shared channels - if err := p.registerForSharedChannels(); err != nil { - p.logger.LogError("Failed to register for shared channels", "error", err) - return fmt.Errorf("failed to register for shared channels: %w", err) - } - // Initialize bridge manager - p.bridgeManager = bridge.NewBridgeManager(p.logger, p.API, p.remoteID) + p.bridgeManager = bridge.NewManager(p.logger) // Initialize and register bridges with current configuration if err := p.initBridges(*cfg); err != nil { @@ -129,10 +118,6 @@ func (p *Plugin) OnDeactivate() error { } } - if err := p.API.UnregisterPluginForSharedChannels(manifest.Id); err != nil { - p.API.LogError("Failed to unregister plugin for shared channels", "err", err) - } - return nil } @@ -153,69 +138,24 @@ func (p *Plugin) initXMPPClient() { cfg.XMPPPassword, cfg.GetXMPPResource(), p.remoteID, - p.logger, ) } func (p *Plugin) initBridges(cfg config.Configuration) error { // Create and register XMPP bridge - xmppBridge := xmppbridge.NewBridge( + bridge := xmppbridge.NewBridge( p.logger, p.API, p.kvstore, &cfg, ) - if err := p.bridgeManager.RegisterBridge("xmpp", xmppBridge); err != nil { + if err := p.bridgeManager.RegisterBridge("xmpp", bridge); err != nil { return fmt.Errorf("failed to register XMPP bridge: %w", err) } - // Create and register Mattermost bridge - mattermostBridge := mattermostbridge.NewBridge( - p.logger, - p.API, - p.kvstore, - &cfg, - ) - - if err := p.bridgeManager.RegisterBridge("mattermost", mattermostBridge); err != nil { - return fmt.Errorf("failed to register Mattermost bridge: %w", err) - } - p.logger.LogInfo("Bridge instances created and registered successfully") return nil } -func (p *Plugin) registerForSharedChannels() error { - botUserID, err := p.API.EnsureBotUser(&model.Bot{ - Username: "mattermost-bridge", - DisplayName: "Mattermost Bridge", - Description: "Mattermost Bridge Bot", - }) - if err != nil { - return fmt.Errorf("failed to ensure bot user: %w", err) - } - - p.botUserID = botUserID - - opts := model.RegisterPluginOpts{ - Displayname: "XMPP-Bridge", - PluginID: manifest.Id, - CreatorID: botUserID, - AutoShareDMs: false, - AutoInvited: true, - } - - remoteID, appErr := p.API.RegisterPluginForSharedChannels(opts) - if appErr != nil { - return fmt.Errorf("failed to register plugin for shared channels: %w", appErr) - } - - // Store the remote ID for use in sync operations - p.remoteID = remoteID - - p.logger.LogInfo("Successfully registered plugin for shared channels", "remote_id", remoteID) - return nil -} - // See https://developers.mattermost.com/extend/plugins/server/reference/ diff --git a/server/xmpp/client.go b/server/xmpp/client.go index aad5e24..4a49ac8 100644 --- a/server/xmpp/client.go +++ b/server/xmpp/client.go @@ -8,10 +8,8 @@ import ( "fmt" "time" - "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/logger" "mellium.im/sasl" "mellium.im/xmpp" - "mellium.im/xmpp/disco" "mellium.im/xmpp/jid" "mellium.im/xmpp/muc" "mellium.im/xmpp/mux" @@ -24,19 +22,18 @@ type Client struct { username string password string resource string - remoteID string // Plugin remote ID for metadata - serverDomain string // explicit server domain for testing - tlsConfig *tls.Config // custom TLS configuration - logger logger.Logger // Logger for debugging + remoteID string // Plugin remote ID for metadata + serverDomain string // explicit server domain for testing + tlsConfig *tls.Config // custom TLS configuration // XMPP connection - session *xmpp.Session - jidAddr jid.JID - ctx context.Context - cancel context.CancelFunc - mucClient *muc.Client - mux *mux.ServeMux - sessionReady chan struct{} + session *xmpp.Session + jidAddr jid.JID + ctx context.Context + cancel context.CancelFunc + mucClient *muc.Client + mux *mux.ServeMux + sessionReady chan struct{} sessionServing bool } @@ -55,21 +52,6 @@ type SendMessageResponse struct { StanzaID string `json:"stanza_id"` } -// MessageBody represents the body element of an XMPP message -type MessageBody struct { - XMLName xml.Name `xml:"body"` - Text string `xml:",chardata"` -} - -// XMPPMessage represents a complete XMPP message stanza -type XMPPMessage struct { - XMLName xml.Name `xml:"jabber:client message"` - Type string `xml:"type,attr"` - To string `xml:"to,attr"` - From string `xml:"from,attr"` - Body MessageBody `xml:"body"` -} - // GhostUser represents an XMPP ghost user type GhostUser struct { JID string `json:"jid"` @@ -83,18 +65,17 @@ type UserProfile struct { } // NewClient creates a new XMPP client. -func NewClient(serverURL, username, password, resource, remoteID string, logger logger.Logger) *Client { +func NewClient(serverURL, username, password, resource, remoteID string) *Client { ctx, cancel := context.WithCancel(context.Background()) mucClient := &muc.Client{} mux := mux.New("jabber:client", muc.HandleClient(mucClient)) - + return &Client{ serverURL: serverURL, username: username, password: password, resource: resource, remoteID: remoteID, - logger: logger, ctx: ctx, cancel: cancel, mucClient: mucClient, @@ -104,8 +85,8 @@ func NewClient(serverURL, username, password, resource, remoteID string, logger } // NewClientWithTLS creates a new XMPP client with custom TLS configuration. -func NewClientWithTLS(serverURL, username, password, resource, remoteID string, tlsConfig *tls.Config, logger logger.Logger) *Client { - client := NewClient(serverURL, username, password, resource, remoteID, logger) +func NewClientWithTLS(serverURL, username, password, resource, remoteID string, tlsConfig *tls.Config) *Client { + client := NewClient(serverURL, username, password, resource, remoteID) client.tlsConfig = tlsConfig return client } @@ -183,11 +164,11 @@ func (c *Client) serveSession() { close(c.sessionReady) // Signal failure return } - + // Signal that the session is ready to serve c.sessionServing = true close(c.sessionReady) - + err := c.session.Serve(c.mux) if err != nil { c.sessionServing = false @@ -221,6 +202,23 @@ func (c *Client) Disconnect() error { return nil } +// TestConnection tests the XMPP connection +func (c *Client) TestConnection() error { + if c.session == nil { + if err := c.Connect(); err != nil { + return err + } + } + + // For now, just check if session exists and is not closed + // A proper ping implementation would require more complex IQ handling + if c.session == nil { + return fmt.Errorf("XMPP session is not established") + } + + return nil +} + // JoinRoom joins an XMPP Multi-User Chat room func (c *Client) JoinRoom(roomJID string) error { if c.session == nil { @@ -253,7 +251,7 @@ func (c *Client) JoinRoom(roomJID string) error { opts := []muc.Option{ muc.MaxBytes(0), // Don't limit message history } - + // Run the join operation in a goroutine to avoid blocking errChan := make(chan error, 1) go func() { @@ -326,12 +324,26 @@ func (c *Client) SendMessage(req MessageRequest) (*SendMessageResponse, error) { sendCtx, cancel := context.WithTimeout(c.ctx, 10*time.Second) defer cancel() + // Create the message body structure + type messageBody struct { + XMLName xml.Name `xml:"body"` + Text string `xml:",chardata"` + } + // Create complete message with body - fullMsg := XMPPMessage{ + type message struct { + XMLName xml.Name `xml:"jabber:client message"` + Type string `xml:"type,attr"` + To string `xml:"to,attr"` + From string `xml:"from,attr"` + Body messageBody `xml:"body"` + } + + fullMsg := message{ Type: "groupchat", To: to.String(), From: c.jidAddr.String(), - Body: MessageBody{Text: req.Message}, + Body: messageBody{Text: req.Message}, } // Send the message using the session encoder @@ -347,39 +359,6 @@ func (c *Client) SendMessage(req MessageRequest) (*SendMessageResponse, error) { return response, nil } -// SendDirectMessage sends a direct message to a specific user -func (c *Client) SendDirectMessage(userJID, message string) error { - if c.session == nil { - if err := c.Connect(); err != nil { - return err - } - } - - to, err := jid.Parse(userJID) - if err != nil { - return fmt.Errorf("failed to parse user JID: %w", err) - } - - // Create a context with timeout for the send operation - sendCtx, cancel := context.WithTimeout(c.ctx, 10*time.Second) - defer cancel() - - // Create direct message using reusable structs - msg := XMPPMessage{ - Type: "chat", - To: to.String(), - From: c.jidAddr.String(), - Body: MessageBody{Text: message}, - } - - // Send the message using the session encoder - if err := c.session.Encode(sendCtx, msg); err != nil { - return fmt.Errorf("failed to send direct message: %w", err) - } - - return nil -} - // ResolveRoomAlias resolves a room alias to room JID func (c *Client) ResolveRoomAlias(roomAlias string) (string, error) { // For XMPP, return the alias as-is if it's already a valid JID @@ -417,121 +396,3 @@ func (c *Client) SetOnlinePresence() error { return nil } - -// CheckRoomExists verifies if an XMPP room exists and is accessible using disco#info -func (c *Client) CheckRoomExists(roomJID string) (bool, error) { - if c.session == nil { - return false, fmt.Errorf("XMPP session not established") - } - - c.logger.LogDebug("Checking room existence using disco#info", "room_jid", roomJID) - - // Parse and validate the room JID - roomAddr, err := jid.Parse(roomJID) - if err != nil { - c.logger.LogError("Invalid room JID", "room_jid", roomJID, "error", err) - return false, fmt.Errorf("invalid room JID: %w", err) - } - - // Set timeout for the disco query - ctx, cancel := context.WithTimeout(c.ctx, 10*time.Second) - defer cancel() - - // Perform disco#info query to the room - info, err := disco.GetInfo(ctx, "", roomAddr, c.session) - if err != nil { - // Check if it's a service-unavailable or item-not-found error - if stanzaErr, ok := err.(stanza.Error); ok { - c.logger.LogDebug("Received stanza error during disco#info query", - "room_jid", roomJID, - "error_condition", string(stanzaErr.Condition), - "error_type", string(stanzaErr.Type)) - - switch stanzaErr.Condition { - case stanza.ServiceUnavailable, stanza.ItemNotFound: - c.logger.LogDebug("Room does not exist", "room_jid", roomJID, "condition", string(stanzaErr.Condition)) - return false, nil // Room doesn't exist - case stanza.Forbidden: - c.logger.LogWarn("Access denied to room (room exists but not accessible)", "room_jid", roomJID) - return false, fmt.Errorf("access denied to room %s", roomJID) - case stanza.NotAuthorized: - c.logger.LogWarn("Not authorized to query room (room exists but not queryable)", "room_jid", roomJID) - return false, fmt.Errorf("not authorized to query room %s", roomJID) - default: - c.logger.LogError("Unexpected disco query error", "room_jid", roomJID, "condition", string(stanzaErr.Condition), "error", err) - return false, fmt.Errorf("disco query failed: %w", err) - } - } - c.logger.LogError("Disco query error", "room_jid", roomJID, "error", err) - return false, fmt.Errorf("disco query error: %w", err) - } - - c.logger.LogDebug("Received disco#info response, checking for MUC features", - "room_jid", roomJID, - "features_count", len(info.Features), - "identities_count", len(info.Identity)) - - // Verify it's actually a MUC room by checking features - for _, feature := range info.Features { - if feature.Var == muc.NS { // "http://jabber.org/protocol/muc" - c.logger.LogDebug("Room exists and has MUC feature", "room_jid", roomJID) - return true, nil - } - } - - // Check for conference identity as backup verification - for _, identity := range info.Identity { - if identity.Category == "conference" { - c.logger.LogDebug("Room exists and has conference identity", "room_jid", roomJID, "identity_type", identity.Type) - return true, nil - } - } - - // Log all features and identities for debugging - c.logger.LogDebug("Room exists but doesn't appear to be a MUC room", - "room_jid", roomJID, - "features", func() []string { - var features []string - for _, f := range info.Features { - features = append(features, f.Var) - } - return features - }(), - "identities", func() []string { - var identities []string - for _, i := range info.Identity { - identities = append(identities, fmt.Sprintf("%s/%s", i.Category, i.Type)) - } - return identities - }()) - - return false, nil -} - -// Ping sends a lightweight ping to the XMPP server to test connectivity -func (c *Client) Ping() error { - if c.session == nil { - return fmt.Errorf("XMPP session not established") - } - - c.logger.LogDebug("Sending XMPP ping to test connectivity") - - // Create a context with timeout for the ping - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - start := time.Now() - - // Use disco#info query to server domain as a connectivity test - // This is a standard, lightweight XMPP operation that all servers support - _, err := disco.GetInfo(ctx, "", c.jidAddr.Domain(), c.session) - if err != nil { - duration := time.Since(start) - c.logger.LogDebug("XMPP ping failed", "error", err, "duration", duration) - return fmt.Errorf("XMPP server ping failed: %w", err) - } - - duration := time.Since(start) - c.logger.LogDebug("XMPP ping successful", "duration", duration) - return nil -}