mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-07 23:13:11 -06:00
Upstream release v0.9.0 (#18)
* Correctly redact events over federation (#2526) * Ensure we check powerlevel/origin before redacting an event * Add passing test * Use pl.UserLevel * Make check more readable, also check for the sender * Add new next steps page to the documentation * Highlighting in docs * Rename the page to "Optimise your installation" * Attempt to raise the file descriptor limit at startup (#2527) * Add `--difference` to `resolve-state` tool * Make the linter happy again * generic CaddyFile in front of Dendrite (monolith) (#2531) for Caddy 2.5.x Co-authored-by: emanuele.aliberti <emanuele.aliberti@mtka.eu> * Handle state before, send history visibility in output (#2532) * Check state before event * Tweaks * Refactor a bit, include in output events * Don't waste time if soft failed either * Tweak control flow, comments, use GMSL history visibility type * Fix rare panic when returning user devices over federation (#2534) * Add `InputDeviceListUpdate` to the keyserver, remove old input API (#2536) * Add `InputDeviceListUpdate` to the keyserver, remove old input API * Fix copyright * Log more information when a device list update fails * Fix nats.go commit (#2540) Signed-off-by: Jean Lucas <jean@4ray.co> * Don't return `end` if there are not more messages (#2542) * Be more spec compliant * Move lazyLoadMembers to own method * Return an error if trying to invite a malformed user ID (#2543) * Add `evacuateUser` endpoint, use it when deactivating accounts (#2545) * Add `evacuateUser` endpoint, use it when deactivating accounts * Populate the API * Clean up user devices when deactivating * Include invites, delete pushers * Silence presence logs (#2547) * Blacklist `Guest users can join guest_access rooms` test until it can be investigated * Disable WebAssembly builds for now * Try to fix backfilling (#2548) * Try to fix backfilling * Return start/end to not confuse clients * Update GMSL * Update GMSL * Roomserver producers package (#2546) * Give the roomserver a producers package * Change init point * Populate ACLs API * Fix build issues * `RoomEventProducer` naming * Version 0.8.9 (#2549) * Version 0.8.9 * Update changelog * feat+fix: Ignore unknown keys and verify required fields are present in appservice registration files (#2550) * fix: ignore unknown keys in appservice configs fixes matrix-org/dendrite#1567 * feat: verify required fields in appservice configs * Use new testrig for key changes tests (#2552) * Use new testrig for tests * Log the error message * Fix QuerySharedUsers for the SyncAPI keychange consumer (#2554) * Make more use of base.BaseDendrite * Fix QuerySharedUsers if no UserIDs are supplied * Return clearer error when no state NID exists for an event (#2555) * Wrap error from `SnapshotNIDFromEventID` * Hopefully fix read receipts timestamps (#2557) This should avoid coercions between signed and unsigned ints which might fix problems like `sql: converting argument $5 type: uint64 values with high bit set are not supported`. * Fix nil pointer access when redacting events (#2560) * Fix issue `uint64 values with high bit are not supported` in presence (#2562) * Fix issue #2528 * Use gomatrixserverlib.Timestamp * Use ParseUint instead of ParseInt * Update Pinecone to matrix-org/pinecone@1ce778f * Ristretto cache (#2563) * Try Ristretto cache * Tweak * It's beautiful * Update GMSL * More strict keyable interface * Fix that some more * Make less panicky * Don't enforce mutability checks for now * Determine mutability using deep equality * Tweaks * Namespace keys * Make federation caches mutable * Update cost estimation, add metric * Update GMSL * Estimate cost for metrics better * Reduce counters a bit * Try caching events * Some guards * Try again * Try this * Use separate caches for hopefully better hash distribution * Fix bug with admitting events into cache * Try to fix bugs * Check nil * Try that again * Preserve order jeezo this is messy * thanks VS Code for doing exactly the wrong thing * Try this again * Be more specific * aaaaargh * One more time * That might be better * Stronger sorting * Cache expiries, async publishing of EDUs * Put it back * Use a shared cache again * Cost estimation fixes * Update ristretto * Reduce counters a bit * Clean up a bit * Update GMSL * 1GB * Configurable cache sizees * Tweaks * Add `config.DataUnit` for specifying friendly cache sizes * Various tweaks * Update GMSL * Add back some lazy loading caching * Include key in cost * Include key in cost * Tweak max age handling, config key name * Only register prometheus metrics if requested * Review comments @S7evinK * Don't return errors when creating caches (it is better just to crash since otherwise we'll `nil`-pointer exception everywhere) * Review comments * Update sample configs * Update GHA Workflow * Update Complement images to Go 1.18 * Remove the cache test from the federation API as we no longer guarantee immediate cache admission * Don't check the caches in the renewal test * Possibly fix the upgrade tests * Update to matrix-org/gomatrixserverlib#322 * Update documentation to refer to Go 1.18 * Minor SendToDevice fix (#2565) * Avoid unnecessary marshalling if sending to the local server * Fix ordering of ToDevice messages * Revive SendToDevice test * Use `/v3` to request media from remote servers (update to matrix-org/gomatrixserverlib#324) * Pointerise `types.RoomInfo` in the cache so we can update it in-place in the latest events updater * Add a Troubleshooting page * Update `sytest-whitelist` * Use sync API database in `filterSharedUsers` (#2572) * Add function to the sync API storage package for filtering shared users * Use the database instead of asking the RS API * Fix unit tests * Fix map handling in `filterSharedUsers` * Update 1_createusers.md (#2571) * Update 1_createusers.md Added description on how to create user accounts when running in docker. * Update 1_createusers.md Co-authored-by: Neil Alexander <neilalexander@users.noreply.github.com> * Fix connection_string format in dendrite-sample.polylith.yaml (#2574) * History visibility database changes (#2533) * Add new history_visibility column * Update SQL queries to include history_visibility * Store the history visibilty calculated by the roomserver * Update GMSL * Update migrations * Fix migration * Update GMSL * Fix `go.sum` * Update GMSL to use sql.Scanner & sql.Valuer * Re-order migration/table creation * Update gomatrixserverlib * Add history_visibility column to current_room_state * Fix migrations * Return error instead of Fatal log Co-authored-by: Neil Alexander <neilalexander@users.noreply.github.com> * Tweak cache counters (#2575) * Tweak cache counters This makes the number of counters relative to the maximum cache size. Since the counters effectively manage the size of the bloom filter, larger caches need more counters and smaller caches need less. 10 counters per 1KB data means that the default cache size of 1GB should result in a bloom filter and TinyLRU admission set of about 16MB estimated. * Remove line left by accident * Set historyVisibility in rowsToStreamEvents * Update FAQ * Add event state key cache (#2576) * Explain how SRV works in Matrix and discourage using it (#2577) * Explain how SRV works in Matrix and discourage using it * Minor tweaks to formatting Co-authored-by: Neil Alexander <neilalexander@users.noreply.github.com> * Fix issue with membership event_nid being 0 (#2580) * docs: Add build page; correct proxy info; fix Caddy example (#2579) * Add build page; correct proxy info; fix Caddy example * Improve Caddyfile example * Apply review comments; add polylith Caddyfile * Bump tzinfo from 1.2.9 to 1.2.10 in /docs (#2584) Bumps [tzinfo](https://github.com/tzinfo/tzinfo) from 1.2.9 to 1.2.10. - [Release notes](https://github.com/tzinfo/tzinfo/releases) - [Changelog](https://github.com/tzinfo/tzinfo/blob/master/CHANGES.md) - [Commits](https://github.com/tzinfo/tzinfo/compare/v1.2.9...v1.2.10) --- updated-dependencies: - dependency-name: tzinfo dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Membership updater refactoring (#2541) * Membership updater refactoring * Pass in membership state * Use membership check rather than referring to state directly * Delete irrelevant membership states * We don't need the leave event after all * Tweaks * Put a log entry in that I might stand a chance of finding * Be less panicky * Tweak invite handling * Don't freak if we can't find the event NID * Use event NID from `types.Event` * Clean up * Better invite handling * Placate the almighty linter * Blacklist a Sytest which is otherwise fine under Complement for reasons I don't understand * Fix the sytest after all (thanks @S7evinK for the spot) * Try to fix HTTP 500s on `/members` (#2581) * Update database migrations, remove goose (#2264) * Add new db migration * Update migrations Remove goose * Add possibility to test direct upgrades * Try to fix WASM test * Add checks for specific migrations * Remove AddMigration Use WithTransaction Add Dendrite version to table * Fix linter issues * Update tests * Update comments, outdent if * Namespace migrations * Add direct upgrade tests, skipping over one version * Split migrations * Update go version in CI * Fix copy&paste mistake * Use contexts in migrations Co-authored-by: kegsay <kegan@matrix.org> Co-authored-by: Neil Alexander <neilalexander@users.noreply.github.com> * Add .well-known/matrix/client to clientapi (#2551) Signed-off-by: Jonathan Bartlett <jonathan@jonnobrow.co.uk> Co-authored-by: Neil Alexander <neilalexander@users.noreply.github.com> * Remove `room_id` field from MSC2946 stripped events (closes #2588) * Remove `goose` from Dockerfiles * Make the User API responsible for sending account data output events (#2592) * Make the User API responsible for sending account data output events * Clean up producer * Review comments * Update NATS Server and nats.go to use upstream * Set CORS headers for HTTP 404 and 405 errors (#2599) * Set CORS headers for the 404s * Use custom handlers, plus one for HTTP 405 too * Tweak setup * Add to muxes too * Tidy up some more * Use built-in HTTP 404 handler * Don't bother setting it for federation-facing * Optimise checking other servers allowed to see events (#2596) * Try optimising checking if server is allowed to see event * Fix error * Handle case where snapshot NID is 0 * Fix query * Update SQL * Clean up `CheckServerAllowedToSeeEvent` * Not supported on SQLite * Maybe placate the unit tests * Review comments * De-race `types.RoomInfo` (#2600) * De-race `CompleteSync` (#2601) The `err` was coming from outside of the goroutine and being written to by concurrent goroutines. * Version 0.9.0 (#2602) Co-authored-by: Till <2353100+S7evinK@users.noreply.github.com> Co-authored-by: Neil Alexander <neilalexander@users.noreply.github.com> Co-authored-by: Till Faelligen <davidf@element.io> Co-authored-by: Emanuele Aliberti <dev@mtka.eu> Co-authored-by: emanuele.aliberti <emanuele.aliberti@mtka.eu> Co-authored-by: Jean Lucas <jean@4ray.co> Co-authored-by: Kabir Kwatra <kabir@kwatra.me> Co-authored-by: andreever <52261463+andreever@users.noreply.github.com> Co-authored-by: Maximilian Gaedig <38767445+MaximilianGaedig@users.noreply.github.com> Co-authored-by: Tulir Asokan <tulir@maunium.net> Co-authored-by: Matt Holt <mholt@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: kegsay <kegan@matrix.org> Co-authored-by: Jonathan Bartlett <34320158+Jonnobrow@users.noreply.github.com>
This commit is contained in:
parent
8903184fe8
commit
15cfeb16aa
29
.github/workflows/dendrite.yml
vendored
29
.github/workflows/dendrite.yml
vendored
|
|
@ -131,7 +131,7 @@ jobs:
|
||||||
- name: Setup go
|
- name: Setup go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: "1.16"
|
go-version: "1.18"
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
|
|
@ -145,6 +145,31 @@ jobs:
|
||||||
- name: Test upgrade
|
- name: Test upgrade
|
||||||
run: ./dendrite-upgrade-tests --head .
|
run: ./dendrite-upgrade-tests --head .
|
||||||
|
|
||||||
|
# run database upgrade tests, skipping over one version
|
||||||
|
upgrade_test_direct:
|
||||||
|
name: Upgrade tests from HEAD-2
|
||||||
|
timeout-minutes: 20
|
||||||
|
needs: initial-tests-done
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Setup go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: "1.18"
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cache/go-build
|
||||||
|
~/go/pkg/mod
|
||||||
|
key: ${{ runner.os }}-go-upgrade-${{ hashFiles('**/go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-go-upgrade
|
||||||
|
- name: Build upgrade-tests
|
||||||
|
run: go build ./cmd/dendrite-upgrade-tests
|
||||||
|
- name: Test upgrade
|
||||||
|
run: ./dendrite-upgrade-tests -direct -from HEAD-2 --head .
|
||||||
|
|
||||||
# run Sytest in different variations
|
# run Sytest in different variations
|
||||||
sytest:
|
sytest:
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
|
|
@ -280,7 +305,7 @@ jobs:
|
||||||
|
|
||||||
integration-tests-done:
|
integration-tests-done:
|
||||||
name: Integration tests passed
|
name: Integration tests passed
|
||||||
needs: [initial-tests-done, upgrade_test, sytest, complement]
|
needs: [initial-tests-done, upgrade_test, upgrade_test_direct, sytest, complement]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ !cancelled() }} # Run this even if prior jobs were skipped
|
if: ${{ !cancelled() }} # Run this even if prior jobs were skipped
|
||||||
steps:
|
steps:
|
||||||
|
|
|
||||||
30
CHANGES.md
30
CHANGES.md
|
|
@ -1,5 +1,35 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Dendrite 0.9.0 (2022-08-01)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Dendrite now uses Ristretto for managing in-memory caches
|
||||||
|
* Should improve cache utilisation considerably over time by more intelligently selecting and managing cache entries compared to the previous LRU-based cache
|
||||||
|
* Defaults to a 1GB cache size if not configured otherwise
|
||||||
|
* The estimated cache size in memory and maximum age can now be configured with new [configuration options](https://github.com/matrix-org/dendrite/blob/e94ef84aaba30e12baf7f524c4e7a36d2fdeb189/dendrite-sample.monolith.yaml#L44-L61) to prevent unbounded cache growth
|
||||||
|
* Added support for serving the `/.well-known/matrix/client` hint directly from Dendrite
|
||||||
|
* Configurable with the new [configuration option](https://github.com/matrix-org/dendrite/blob/e94ef84aaba30e12baf7f524c4e7a36d2fdeb189/dendrite-sample.monolith.yaml#L67-L69)
|
||||||
|
* Refactored membership updater, which should eliminate some bugs caused by the membership table getting out of sync with the room state
|
||||||
|
* The User API is now responsible for sending account data updates to other components, which may fix some races and duplicate account data events
|
||||||
|
* Optimised database query for checking whether a remote server is allowed to request an event over federation without using anywhere near as much CPU time (PostgreSQL only)
|
||||||
|
* Database migrations have been refactored to eliminate some problems that were present with `goose` and upgrading from older Dendrite versions
|
||||||
|
* Media fetching will now use the `/v3` endpoints for downloading media from remote homeservers
|
||||||
|
* HTTP 404 and HTTP 405 errors from the client-facing APIs should now be returned with CORS headers so that web-based clients do not produce incorrect access control warnings for unknown endpoints
|
||||||
|
* Some preparation work for full history visibility support
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Fixes a crash that could occur during event redaction
|
||||||
|
* The `/members` endpoint will no longer incorrectly return HTTP 500 as a result of some invite events
|
||||||
|
* Send-to-device messages should now be ordered more reliably and the last position in the stream updated correctly
|
||||||
|
* Parsing of appservice configuration files is now less strict (contributed by [Kab1r](https://github.com/Kab1r))
|
||||||
|
* The sync API should now identify shared users correctly when waking up for E2EE key changes
|
||||||
|
* The federation `/state` endpoint will now return a HTTP 403 when the state before an event isn't known instead of a HTTP 500
|
||||||
|
* Presence timestamps should now be calculated with the correct precision
|
||||||
|
* A race condition in the roomserver's room info has been fixed
|
||||||
|
* A race condition in the sync API has been fixed
|
||||||
|
|
||||||
## Dendrite 0.8.9 (2022-07-01)
|
## Dendrite 0.8.9 (2022-07-01)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ If you have further questions, please take a look at [our FAQ](docs/FAQ.md) or j
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
To build Dendrite, you will need Go 1.16 or later.
|
To build Dendrite, you will need Go 1.18 or later.
|
||||||
|
|
||||||
For a usable federating Dendrite deployment, you will also need:
|
For a usable federating Dendrite deployment, you will also need:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ COPY . /build
|
||||||
|
|
||||||
RUN mkdir -p bin
|
RUN mkdir -p bin
|
||||||
RUN go build -trimpath -o bin/ ./cmd/dendrite-monolith-server
|
RUN go build -trimpath -o bin/ ./cmd/dendrite-monolith-server
|
||||||
RUN go build -trimpath -o bin/ ./cmd/goose
|
|
||||||
RUN go build -trimpath -o bin/ ./cmd/create-account
|
RUN go build -trimpath -o bin/ ./cmd/create-account
|
||||||
RUN go build -trimpath -o bin/ ./cmd/generate-keys
|
RUN go build -trimpath -o bin/ ./cmd/generate-keys
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ COPY . /build
|
||||||
|
|
||||||
RUN mkdir -p bin
|
RUN mkdir -p bin
|
||||||
RUN go build -trimpath -o bin/ ./cmd/dendrite-polylith-multi
|
RUN go build -trimpath -o bin/ ./cmd/dendrite-polylith-multi
|
||||||
RUN go build -trimpath -o bin/ ./cmd/goose
|
|
||||||
RUN go build -trimpath -o bin/ ./cmd/create-account
|
RUN go build -trimpath -o bin/ ./cmd/create-account
|
||||||
RUN go build -trimpath -o bin/ ./cmd/generate-keys
|
RUN go build -trimpath -o bin/ ./cmd/generate-keys
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,7 @@ func (m *DendriteMonolith) Start() {
|
||||||
m.PineconeRouter = pineconeRouter.NewRouter(logrus.WithField("pinecone", "router"), sk, false)
|
m.PineconeRouter = pineconeRouter.NewRouter(logrus.WithField("pinecone", "router"), sk, false)
|
||||||
m.PineconeQUIC = pineconeSessions.NewSessions(logrus.WithField("pinecone", "sessions"), m.PineconeRouter, []string{"matrix"})
|
m.PineconeQUIC = pineconeSessions.NewSessions(logrus.WithField("pinecone", "sessions"), m.PineconeRouter, []string{"matrix"})
|
||||||
m.PineconeMulticast = pineconeMulticast.NewMulticast(logrus.WithField("pinecone", "multicast"), m.PineconeRouter)
|
m.PineconeMulticast = pineconeMulticast.NewMulticast(logrus.WithField("pinecone", "multicast"), m.PineconeRouter)
|
||||||
m.PineconeManager = pineconeConnections.NewConnectionManager(m.PineconeRouter)
|
m.PineconeManager = pineconeConnections.NewConnectionManager(m.PineconeRouter, nil)
|
||||||
|
|
||||||
prefix := hex.EncodeToString(pk)
|
prefix := hex.EncodeToString(pk)
|
||||||
cfg := &config.Dendrite{}
|
cfg := &config.Dendrite{}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
FROM golang:1.16-stretch as build
|
FROM golang:1.18-stretch as build
|
||||||
RUN apt-get update && apt-get install -y sqlite3
|
RUN apt-get update && apt-get install -y sqlite3
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
|
|
@ -27,6 +27,6 @@ EXPOSE 8008 8448
|
||||||
# At runtime, generate TLS cert based on the CA now mounted at /ca
|
# At runtime, generate TLS cert based on the CA now mounted at /ca
|
||||||
# At runtime, replace the SERVER_NAME with what we are told
|
# At runtime, replace the SERVER_NAME with what we are told
|
||||||
CMD ./generate-keys --server $SERVER_NAME --tls-cert server.crt --tls-key server.key --tls-authority-cert /complement/ca/ca.crt --tls-authority-key /complement/ca/ca.key && \
|
CMD ./generate-keys --server $SERVER_NAME --tls-cert server.crt --tls-key server.key --tls-authority-cert /complement/ca/ca.crt --tls-authority-key /complement/ca/ca.key && \
|
||||||
./generate-config -server $SERVER_NAME --ci > dendrite.yaml && \
|
./generate-config -server $SERVER_NAME --ci > dendrite.yaml && \
|
||||||
cp /complement/ca/ca.crt /usr/local/share/ca-certificates/ && update-ca-certificates && \
|
cp /complement/ca/ca.crt /usr/local/share/ca-certificates/ && update-ca-certificates && \
|
||||||
./dendrite-monolith-server --really-enable-open-registration --tls-cert server.crt --tls-key server.key --config dendrite.yaml -api=${API:-0}
|
./dendrite-monolith-server --really-enable-open-registration --tls-cert server.crt --tls-key server.key --config dendrite.yaml -api=${API:-0}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
#
|
#
|
||||||
# Use these mounts to make use of this dockerfile:
|
# Use these mounts to make use of this dockerfile:
|
||||||
# COMPLEMENT_HOST_MOUNTS='/your/local/dendrite:/dendrite:ro;/your/go/path:/go:ro'
|
# COMPLEMENT_HOST_MOUNTS='/your/local/dendrite:/dendrite:ro;/your/go/path:/go:ro'
|
||||||
FROM golang:1.16-stretch
|
FROM golang:1.18-stretch
|
||||||
RUN apt-get update && apt-get install -y sqlite3
|
RUN apt-get update && apt-get install -y sqlite3
|
||||||
|
|
||||||
WORKDIR /runtime
|
WORKDIR /runtime
|
||||||
|
|
@ -16,24 +16,24 @@ EXPOSE 8008 8448
|
||||||
|
|
||||||
# This script compiles Dendrite for us.
|
# This script compiles Dendrite for us.
|
||||||
RUN echo '\
|
RUN echo '\
|
||||||
#!/bin/bash -eux \n\
|
#!/bin/bash -eux \n\
|
||||||
if test -f "/runtime/dendrite-monolith-server"; then \n\
|
if test -f "/runtime/dendrite-monolith-server"; then \n\
|
||||||
echo "Skipping compilation; binaries exist" \n\
|
echo "Skipping compilation; binaries exist" \n\
|
||||||
exit 0 \n\
|
exit 0 \n\
|
||||||
fi \n\
|
fi \n\
|
||||||
cd /dendrite \n\
|
cd /dendrite \n\
|
||||||
go build -v -o /runtime /dendrite/cmd/dendrite-monolith-server \n\
|
go build -v -o /runtime /dendrite/cmd/dendrite-monolith-server \n\
|
||||||
' > compile.sh && chmod +x compile.sh
|
' > compile.sh && chmod +x compile.sh
|
||||||
|
|
||||||
# This script runs Dendrite for us. Must be run in the /runtime directory.
|
# This script runs Dendrite for us. Must be run in the /runtime directory.
|
||||||
RUN echo '\
|
RUN echo '\
|
||||||
#!/bin/bash -eu \n\
|
#!/bin/bash -eu \n\
|
||||||
./generate-keys --private-key matrix_key.pem \n\
|
./generate-keys --private-key matrix_key.pem \n\
|
||||||
./generate-keys --server $SERVER_NAME --tls-cert server.crt --tls-key server.key --tls-authority-cert /complement/ca/ca.crt --tls-authority-key /complement/ca/ca.key \n\
|
./generate-keys --server $SERVER_NAME --tls-cert server.crt --tls-key server.key --tls-authority-cert /complement/ca/ca.crt --tls-authority-key /complement/ca/ca.key \n\
|
||||||
./generate-config -server $SERVER_NAME --ci > dendrite.yaml \n\
|
./generate-config -server $SERVER_NAME --ci > dendrite.yaml \n\
|
||||||
cp /complement/ca/ca.crt /usr/local/share/ca-certificates/ && update-ca-certificates \n\
|
cp /complement/ca/ca.crt /usr/local/share/ca-certificates/ && update-ca-certificates \n\
|
||||||
./dendrite-monolith-server --really-enable-open-registration --tls-cert server.crt --tls-key server.key --config dendrite.yaml \n\
|
./dendrite-monolith-server --really-enable-open-registration --tls-cert server.crt --tls-key server.key --config dendrite.yaml \n\
|
||||||
' > run.sh && chmod +x run.sh
|
' > run.sh && chmod +x run.sh
|
||||||
|
|
||||||
|
|
||||||
WORKDIR /cache
|
WORKDIR /cache
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
FROM golang:1.16-stretch as build
|
FROM golang:1.18-stretch as build
|
||||||
RUN apt-get update && apt-get install -y postgresql
|
RUN apt-get update && apt-get install -y postgresql
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
|
|
@ -9,16 +9,16 @@ RUN sed -i "s%127.0.0.1/32 md5%127.0.0.1/32 trust%g" /etc/
|
||||||
|
|
||||||
# This entry script starts postgres, waits for it to be up then starts dendrite
|
# This entry script starts postgres, waits for it to be up then starts dendrite
|
||||||
RUN echo '\
|
RUN echo '\
|
||||||
#!/bin/bash -eu \n\
|
#!/bin/bash -eu \n\
|
||||||
pg_lsclusters \n\
|
pg_lsclusters \n\
|
||||||
pg_ctlcluster 9.6 main start \n\
|
pg_ctlcluster 9.6 main start \n\
|
||||||
\n\
|
\n\
|
||||||
until pg_isready \n\
|
until pg_isready \n\
|
||||||
do \n\
|
do \n\
|
||||||
echo "Waiting for postgres"; \n\
|
echo "Waiting for postgres"; \n\
|
||||||
sleep 1; \n\
|
sleep 1; \n\
|
||||||
done \n\
|
done \n\
|
||||||
' > run_postgres.sh && chmod +x run_postgres.sh
|
' > run_postgres.sh && chmod +x run_postgres.sh
|
||||||
|
|
||||||
# we will dump the binaries and config file to this location to ensure any local untracked files
|
# we will dump the binaries and config file to this location to ensure any local untracked files
|
||||||
# that come from the COPY . . file don't contaminate the build
|
# that come from the COPY . . file don't contaminate the build
|
||||||
|
|
@ -46,9 +46,9 @@ EXPOSE 8008 8448
|
||||||
# At runtime, generate TLS cert based on the CA now mounted at /ca
|
# At runtime, generate TLS cert based on the CA now mounted at /ca
|
||||||
# At runtime, replace the SERVER_NAME with what we are told
|
# At runtime, replace the SERVER_NAME with what we are told
|
||||||
CMD /build/run_postgres.sh && ./generate-keys --server $SERVER_NAME --tls-cert server.crt --tls-key server.key --tls-authority-cert /complement/ca/ca.crt --tls-authority-key /complement/ca/ca.key && \
|
CMD /build/run_postgres.sh && ./generate-keys --server $SERVER_NAME --tls-cert server.crt --tls-key server.key --tls-authority-cert /complement/ca/ca.crt --tls-authority-key /complement/ca/ca.key && \
|
||||||
./generate-config -server $SERVER_NAME --ci > dendrite.yaml && \
|
./generate-config -server $SERVER_NAME --ci > dendrite.yaml && \
|
||||||
# Replace the connection string with a single postgres DB, using user/db = 'postgres' and no password, bump max_conns
|
# Replace the connection string with a single postgres DB, using user/db = 'postgres' and no password, bump max_conns
|
||||||
sed -i "s%connection_string:.*$%connection_string: postgresql://postgres@localhost/postgres?sslmode=disable%g" dendrite.yaml && \
|
sed -i "s%connection_string:.*$%connection_string: postgresql://postgres@localhost/postgres?sslmode=disable%g" dendrite.yaml && \
|
||||||
sed -i 's/max_open_conns:.*$/max_open_conns: 100/g' dendrite.yaml && \
|
sed -i 's/max_open_conns:.*$/max_open_conns: 100/g' dendrite.yaml && \
|
||||||
cp /complement/ca/ca.crt /usr/local/share/ca-certificates/ && update-ca-certificates && \
|
cp /complement/ca/ca.crt /usr/local/share/ca-certificates/ && update-ca-certificates && \
|
||||||
./dendrite-monolith-server --really-enable-open-registration --tls-cert server.crt --tls-key server.key --config dendrite.yaml -api=${API:-0}
|
./dendrite-monolith-server --really-enable-open-registration --tls-cert server.crt --tls-key server.key --config dendrite.yaml -api=${API:-0}
|
||||||
|
|
@ -48,7 +48,6 @@ func AddPublicRoutes(
|
||||||
|
|
||||||
syncProducer := &producers.SyncAPIProducer{
|
syncProducer := &producers.SyncAPIProducer{
|
||||||
JetStream: js,
|
JetStream: js,
|
||||||
TopicClientData: cfg.Matrix.JetStream.Prefixed(jetstream.OutputClientData),
|
|
||||||
TopicReceiptEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputReceiptEvent),
|
TopicReceiptEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputReceiptEvent),
|
||||||
TopicSendToDeviceEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputSendToDeviceEvent),
|
TopicSendToDeviceEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputSendToDeviceEvent),
|
||||||
TopicTypingEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputTypingEvent),
|
TopicTypingEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputTypingEvent),
|
||||||
|
|
@ -59,6 +58,7 @@ func AddPublicRoutes(
|
||||||
|
|
||||||
routing.Setup(
|
routing.Setup(
|
||||||
base.PublicClientAPIMux,
|
base.PublicClientAPIMux,
|
||||||
|
base.PublicWellKnownAPIMux,
|
||||||
base.SynapseAdminMux,
|
base.SynapseAdminMux,
|
||||||
base.DendriteAdminMux,
|
base.DendriteAdminMux,
|
||||||
cfg, rsAPI, asAPI,
|
cfg, rsAPI, asAPI,
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,10 @@ package producers
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal/eventutil"
|
|
||||||
"github.com/matrix-org/dendrite/setup/jetstream"
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/dendrite/syncapi/types"
|
"github.com/matrix-org/dendrite/syncapi/types"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
|
|
@ -31,7 +31,6 @@ import (
|
||||||
|
|
||||||
// SyncAPIProducer produces events for the sync API server to consume
|
// SyncAPIProducer produces events for the sync API server to consume
|
||||||
type SyncAPIProducer struct {
|
type SyncAPIProducer struct {
|
||||||
TopicClientData string
|
|
||||||
TopicReceiptEvent string
|
TopicReceiptEvent string
|
||||||
TopicSendToDeviceEvent string
|
TopicSendToDeviceEvent string
|
||||||
TopicTypingEvent string
|
TopicTypingEvent string
|
||||||
|
|
@ -41,36 +40,6 @@ type SyncAPIProducer struct {
|
||||||
UserAPI userapi.ClientUserAPI
|
UserAPI userapi.ClientUserAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendData sends account data to the sync API server
|
|
||||||
func (p *SyncAPIProducer) SendData(userID string, roomID string, dataType string, readMarker *eventutil.ReadMarkerJSON, ignoredUsers *types.IgnoredUsers) error {
|
|
||||||
m := &nats.Msg{
|
|
||||||
Subject: p.TopicClientData,
|
|
||||||
Header: nats.Header{},
|
|
||||||
}
|
|
||||||
m.Header.Set(jetstream.UserID, userID)
|
|
||||||
|
|
||||||
data := eventutil.AccountData{
|
|
||||||
RoomID: roomID,
|
|
||||||
Type: dataType,
|
|
||||||
ReadMarker: readMarker,
|
|
||||||
IgnoredUsers: ignoredUsers,
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
m.Data, err = json.Marshal(data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"user_id": userID,
|
|
||||||
"room_id": roomID,
|
|
||||||
"data_type": dataType,
|
|
||||||
}).Tracef("Producing to topic '%s'", p.TopicClientData)
|
|
||||||
|
|
||||||
_, err = p.JetStream.PublishMsg(m)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SyncAPIProducer) SendReceipt(
|
func (p *SyncAPIProducer) SendReceipt(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
userID, roomID, eventID, receiptType string, timestamp gomatrixserverlib.Timestamp,
|
userID, roomID, eventID, receiptType string, timestamp gomatrixserverlib.Timestamp,
|
||||||
|
|
@ -83,7 +52,7 @@ func (p *SyncAPIProducer) SendReceipt(
|
||||||
m.Header.Set(jetstream.RoomID, roomID)
|
m.Header.Set(jetstream.RoomID, roomID)
|
||||||
m.Header.Set(jetstream.EventID, eventID)
|
m.Header.Set(jetstream.EventID, eventID)
|
||||||
m.Header.Set("type", receiptType)
|
m.Header.Set("type", receiptType)
|
||||||
m.Header.Set("timestamp", strconv.Itoa(int(timestamp)))
|
m.Header.Set("timestamp", fmt.Sprintf("%d", timestamp))
|
||||||
|
|
||||||
log.WithFields(log.Fields{}).Tracef("Producing to topic '%s'", p.TopicReceiptEvent)
|
log.WithFields(log.Fields{}).Tracef("Producing to topic '%s'", p.TopicReceiptEvent)
|
||||||
_, err := p.JetStream.PublishMsg(m, nats.Context(ctx))
|
_, err := p.JetStream.PublishMsg(m, nats.Context(ctx))
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ import (
|
||||||
"github.com/matrix-org/dendrite/clientapi/producers"
|
"github.com/matrix-org/dendrite/clientapi/producers"
|
||||||
"github.com/matrix-org/dendrite/internal/eventutil"
|
"github.com/matrix-org/dendrite/internal/eventutil"
|
||||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/dendrite/syncapi/types"
|
|
||||||
"github.com/matrix-org/dendrite/userapi/api"
|
"github.com/matrix-org/dendrite/userapi/api"
|
||||||
|
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
|
@ -127,18 +126,6 @@ func SaveAccountData(
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ignoredUsers *types.IgnoredUsers
|
|
||||||
if dataType == "m.ignored_user_list" {
|
|
||||||
ignoredUsers = &types.IgnoredUsers{}
|
|
||||||
_ = json.Unmarshal(body, ignoredUsers)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: user API should do this since it's account data
|
|
||||||
if err := syncProducer.SendData(userID, roomID, dataType, nil, ignoredUsers); err != nil {
|
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("syncProducer.SendData failed")
|
|
||||||
return jsonerror.InternalServerError()
|
|
||||||
}
|
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: struct{}{},
|
JSON: struct{}{},
|
||||||
|
|
@ -191,11 +178,6 @@ func SaveReadMarker(
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := syncProducer.SendData(device.UserID, roomID, "m.fully_read", &r, nil); err != nil {
|
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("syncProducer.SendData failed")
|
|
||||||
return jsonerror.InternalServerError()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the read receipt that may be included in the read marker
|
// Handle the read receipt that may be included in the read marker
|
||||||
if r.Read != "" {
|
if r.Read != "" {
|
||||||
return SetReceipt(req, syncProducer, device, roomID, "m.read", r.Read)
|
return SetReceipt(req, syncProducer, device, roomID, "m.read", r.Read)
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
"github.com/matrix-org/dendrite/clientapi/producers"
|
"github.com/matrix-org/dendrite/clientapi/producers"
|
||||||
|
|
@ -98,10 +96,6 @@ func PutTag(
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = syncProducer.SendData(userID, roomID, "m.tag", nil, nil); err != nil {
|
|
||||||
logrus.WithError(err).Error("Failed to send m.tag account data update to syncapi")
|
|
||||||
}
|
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: struct{}{},
|
JSON: struct{}{},
|
||||||
|
|
@ -150,11 +144,6 @@ func DeleteTag(
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: user API should do this since it's account data
|
|
||||||
if err := syncProducer.SendData(userID, roomID, "m.tag", nil, nil); err != nil {
|
|
||||||
logrus.WithError(err).Error("Failed to send m.tag account data update to syncapi")
|
|
||||||
}
|
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: struct{}{},
|
JSON: struct{}{},
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ import (
|
||||||
// applied:
|
// applied:
|
||||||
// nolint: gocyclo
|
// nolint: gocyclo
|
||||||
func Setup(
|
func Setup(
|
||||||
publicAPIMux, synapseAdminRouter, dendriteAdminRouter *mux.Router,
|
publicAPIMux, wkMux, synapseAdminRouter, dendriteAdminRouter *mux.Router,
|
||||||
cfg *config.ClientAPI,
|
cfg *config.ClientAPI,
|
||||||
rsAPI roomserverAPI.ClientRoomserverAPI,
|
rsAPI roomserverAPI.ClientRoomserverAPI,
|
||||||
asAPI appserviceAPI.AppServiceInternalAPI,
|
asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
|
|
@ -76,6 +76,26 @@ func Setup(
|
||||||
unstableFeatures["org.matrix."+msc] = true
|
unstableFeatures["org.matrix."+msc] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.Matrix.WellKnownClientName != "" {
|
||||||
|
logrus.Infof("Setting m.homeserver base_url as %s at /.well-known/matrix/client", cfg.Matrix.WellKnownClientName)
|
||||||
|
wkMux.Handle("/client", httputil.MakeExternalAPI("wellknown", func(r *http.Request) util.JSONResponse {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: struct {
|
||||||
|
HomeserverName struct {
|
||||||
|
BaseUrl string `json:"base_url"`
|
||||||
|
} `json:"m.homeserver"`
|
||||||
|
}{
|
||||||
|
HomeserverName: struct {
|
||||||
|
BaseUrl string `json:"base_url"`
|
||||||
|
}{
|
||||||
|
BaseUrl: cfg.Matrix.WellKnownClientName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
}
|
||||||
|
|
||||||
publicAPIMux.Handle("/versions",
|
publicAPIMux.Handle("/versions",
|
||||||
httputil.MakeExternalAPI("versions", func(req *http.Request) util.JSONResponse {
|
httputil.MakeExternalAPI("versions", func(req *http.Request) util.JSONResponse {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ func main() {
|
||||||
pRouter := pineconeRouter.NewRouter(logrus.WithField("pinecone", "router"), sk, false)
|
pRouter := pineconeRouter.NewRouter(logrus.WithField("pinecone", "router"), sk, false)
|
||||||
pQUIC := pineconeSessions.NewSessions(logrus.WithField("pinecone", "sessions"), pRouter, []string{"matrix"})
|
pQUIC := pineconeSessions.NewSessions(logrus.WithField("pinecone", "sessions"), pRouter, []string{"matrix"})
|
||||||
pMulticast := pineconeMulticast.NewMulticast(logrus.WithField("pinecone", "multicast"), pRouter)
|
pMulticast := pineconeMulticast.NewMulticast(logrus.WithField("pinecone", "multicast"), pRouter)
|
||||||
pManager := pineconeConnections.NewConnectionManager(pRouter)
|
pManager := pineconeConnections.NewConnectionManager(pRouter, nil)
|
||||||
pMulticast.Start()
|
pMulticast.Start()
|
||||||
if instancePeer != nil && *instancePeer != "" {
|
if instancePeer != nil && *instancePeer != "" {
|
||||||
pManager.AddPeer(*instancePeer)
|
pManager.AddPeer(*instancePeer)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Yggdrasil Demo
|
# Yggdrasil Demo
|
||||||
|
|
||||||
This is the Dendrite Yggdrasil demo! It's easy to get started - all you need is Go 1.16 or later.
|
This is the Dendrite Yggdrasil demo! It's easy to get started - all you need is Go 1.18 or later.
|
||||||
|
|
||||||
To run the homeserver, start at the root of the Dendrite repository and run:
|
To run the homeserver, start at the root of the Dendrite repository and run:
|
||||||
|
|
||||||
|
|
@ -13,10 +13,10 @@ The following command line arguments are accepted:
|
||||||
* `-peer tcp://a.b.c.d:e` to specify a static Yggdrasil peer to connect to - you will need to supply this if you do not have another Yggdrasil node on your network
|
* `-peer tcp://a.b.c.d:e` to specify a static Yggdrasil peer to connect to - you will need to supply this if you do not have another Yggdrasil node on your network
|
||||||
* `-port 12345` to specify a port to listen on for client connections
|
* `-port 12345` to specify a port to listen on for client connections
|
||||||
|
|
||||||
If you need to find an internet peer, take a look at [this list](https://publicpeers.neilalexander.dev/).
|
If you need to find an internet peer, take a look at [this list](https://publicpeers.neilalexander.dev/).
|
||||||
|
|
||||||
Then point your favourite Matrix client to the homeserver URL`http://localhost:8008` (or whichever `-port` you specified), create an account and log in.
|
Then point your favourite Matrix client to the homeserver URL`http://localhost:8008` (or whichever `-port` you specified), create an account and log in.
|
||||||
|
|
||||||
If your peering connection is operational then you should see a `Connected TCP:` line in the log output. If not then try a different peer.
|
If your peering connection is operational then you should see a `Connected TCP:` line in the log output. If not then try a different peer.
|
||||||
|
|
||||||
Once logged in, you should be able to open the room directory or join a room by its ID.
|
Once logged in, you should be able to open the room directory or join a room by its ID.
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ var (
|
||||||
flagBuildConcurrency = flag.Int("build-concurrency", runtime.NumCPU(), "The amount of build concurrency when building images")
|
flagBuildConcurrency = flag.Int("build-concurrency", runtime.NumCPU(), "The amount of build concurrency when building images")
|
||||||
flagHead = flag.String("head", "", "Location to a dendrite repository to treat as HEAD instead of Github")
|
flagHead = flag.String("head", "", "Location to a dendrite repository to treat as HEAD instead of Github")
|
||||||
flagDockerHost = flag.String("docker-host", "localhost", "The hostname of the docker client. 'localhost' if running locally, 'host.docker.internal' if running in Docker.")
|
flagDockerHost = flag.String("docker-host", "localhost", "The hostname of the docker client. 'localhost' if running locally, 'host.docker.internal' if running in Docker.")
|
||||||
|
flagDirect = flag.Bool("direct", false, "If a direct upgrade from the defined FROM version to TO should be done")
|
||||||
alphaNumerics = regexp.MustCompile("[^a-zA-Z0-9]+")
|
alphaNumerics = regexp.MustCompile("[^a-zA-Z0-9]+")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -48,7 +49,7 @@ const HEAD = "HEAD"
|
||||||
// due to the error:
|
// due to the error:
|
||||||
// When using COPY with more than one source file, the destination must be a directory and end with a /
|
// When using COPY with more than one source file, the destination must be a directory and end with a /
|
||||||
// We need to run a postgres anyway, so use the dockerfile associated with Complement instead.
|
// We need to run a postgres anyway, so use the dockerfile associated with Complement instead.
|
||||||
const Dockerfile = `FROM golang:1.16-stretch as build
|
const Dockerfile = `FROM golang:1.18-stretch as build
|
||||||
RUN apt-get update && apt-get install -y postgresql
|
RUN apt-get update && apt-get install -y postgresql
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
|
|
@ -229,7 +230,7 @@ func getAndSortVersionsFromGithub(httpClient *http.Client) (semVers []*semver.Ve
|
||||||
return semVers, nil
|
return semVers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func calculateVersions(cli *http.Client, from, to string) []string {
|
func calculateVersions(cli *http.Client, from, to string, direct bool) []string {
|
||||||
semvers, err := getAndSortVersionsFromGithub(cli)
|
semvers, err := getAndSortVersionsFromGithub(cli)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to collect semvers from github: %s", err)
|
log.Fatalf("failed to collect semvers from github: %s", err)
|
||||||
|
|
@ -284,6 +285,9 @@ func calculateVersions(cli *http.Client, from, to string) []string {
|
||||||
if to == HEAD {
|
if to == HEAD {
|
||||||
versions = append(versions, HEAD)
|
versions = append(versions, HEAD)
|
||||||
}
|
}
|
||||||
|
if direct {
|
||||||
|
versions = []string{versions[0], versions[len(versions)-1]}
|
||||||
|
}
|
||||||
return versions
|
return versions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -461,7 +465,7 @@ func main() {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
cleanup(dockerClient)
|
cleanup(dockerClient)
|
||||||
versions := calculateVersions(httpClient, *flagFrom, *flagTo)
|
versions := calculateVersions(httpClient, *flagFrom, *flagTo, *flagDirect)
|
||||||
log.Printf("Testing dendrite versions: %v\n", versions)
|
log.Printf("Testing dendrite versions: %v\n", versions)
|
||||||
|
|
||||||
branchToImageID := buildDendriteImages(httpClient, dockerClient, *flagTempDir, *flagBuildConcurrency, versions)
|
branchToImageID := buildDendriteImages(httpClient, dockerClient, *flagTempDir, *flagBuildConcurrency, versions)
|
||||||
|
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
## Database migrations
|
|
||||||
|
|
||||||
We use [goose](https://github.com/pressly/goose) to handle database migrations. This allows us to execute
|
|
||||||
both SQL deltas (e.g `ALTER TABLE ...`) as well as manipulate data in the database in Go using Go functions.
|
|
||||||
|
|
||||||
To run a migration, the `goose` binary in this directory needs to be built:
|
|
||||||
```
|
|
||||||
$ go build ./cmd/goose
|
|
||||||
```
|
|
||||||
|
|
||||||
This binary allows Dendrite databases to be upgraded and downgraded. Sample usage for upgrading the roomserver database:
|
|
||||||
|
|
||||||
```
|
|
||||||
# for sqlite
|
|
||||||
$ ./goose -dir roomserver/storage/sqlite3/deltas sqlite3 ./roomserver.db up
|
|
||||||
|
|
||||||
# for postgres
|
|
||||||
$ ./goose -dir roomserver/storage/postgres/deltas postgres "user=dendrite dbname=dendrite sslmode=disable" up
|
|
||||||
```
|
|
||||||
|
|
||||||
For a full list of options, including rollbacks, see https://github.com/pressly/goose or use `goose` with no args.
|
|
||||||
|
|
||||||
|
|
||||||
### Rationale
|
|
||||||
|
|
||||||
Dendrite creates tables on startup using `CREATE TABLE IF NOT EXISTS`, so you might think that we should also
|
|
||||||
apply version upgrades on startup as well. This is convenient and doesn't involve an additional binary to run
|
|
||||||
which complicates upgrades. However, combining the upgrade mechanism and the server binary makes it difficult
|
|
||||||
to handle rollbacks. Firstly, how do you specify you wish to rollback? We would have to add additional flags
|
|
||||||
to the main server binary to say "rollback to version X". Secondly, if you roll back the server binary from
|
|
||||||
version 5 to version 4, the version 4 binary doesn't know how to rollback the database from version 5 to
|
|
||||||
version 4! For these reasons, we prefer to have a separate "upgrade" binary which is run for database upgrades.
|
|
||||||
Rather than roll-our-own migration tool, we decided to use [goose](https://github.com/pressly/goose) as it supports
|
|
||||||
complex migrations in Go code in addition to just executing SQL deltas. Other alternatives like
|
|
||||||
`github.com/golang-migrate/migrate` [do not support](https://github.com/golang-migrate/migrate/issues/15) these
|
|
||||||
kinds of complex migrations.
|
|
||||||
|
|
||||||
### Adding new deltas
|
|
||||||
|
|
||||||
You can add `.sql` or `.go` files manually or you can use goose to create them for you.
|
|
||||||
|
|
||||||
If you only want to add a SQL delta then run:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ./goose -dir serverkeyapi/storage/sqlite3/deltas sqlite3 ./foo.db create new_col sql
|
|
||||||
2020/09/09 14:37:43 Created new file: serverkeyapi/storage/sqlite3/deltas/20200909143743_new_col.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
In this case, the version number is `20200909143743`. The important thing is that it is always increasing.
|
|
||||||
|
|
||||||
Then add up/downgrade SQL commands to the created file which looks like:
|
|
||||||
```sql
|
|
||||||
-- +goose Up
|
|
||||||
-- +goose StatementBegin
|
|
||||||
SELECT 'up SQL query';
|
|
||||||
-- +goose StatementEnd
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
-- +goose StatementBegin
|
|
||||||
SELECT 'down SQL query';
|
|
||||||
-- +goose StatementEnd
|
|
||||||
|
|
||||||
```
|
|
||||||
You __must__ keep the `+goose` annotations. You'll need to repeat this process for Postgres.
|
|
||||||
|
|
||||||
For complex Go migrations:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ./goose -dir serverkeyapi/storage/sqlite3/deltas sqlite3 ./foo.db create complex_update go
|
|
||||||
2020/09/09 14:40:38 Created new file: serverkeyapi/storage/sqlite3/deltas/20200909144038_complex_update.go
|
|
||||||
```
|
|
||||||
|
|
||||||
Then modify the created `.go` file which looks like:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package migrations
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/pressly/goose"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
goose.AddMigration(upComplexUpdate, downComplexUpdate)
|
|
||||||
}
|
|
||||||
|
|
||||||
func upComplexUpdate(tx *sql.Tx) error {
|
|
||||||
// This code is executed when the migration is applied.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func downComplexUpdate(tx *sql.Tx) error {
|
|
||||||
// This code is executed when the migration is rolled back.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
You __must__ import the package in `/cmd/goose/main.go` so `func init()` gets called.
|
|
||||||
|
|
||||||
|
|
||||||
#### Database limitations
|
|
||||||
|
|
||||||
- SQLite3 does NOT support `ALTER TABLE table_name DROP COLUMN` - you would have to rename the column or drop the table
|
|
||||||
entirely and recreate it. ([example](https://github.com/matrix-org/dendrite/blob/master/userapi/storage/accounts/sqlite3/deltas/20200929203058_is_active.sql))
|
|
||||||
|
|
||||||
More information: [sqlite.org](https://www.sqlite.org/lang_altertable.html)
|
|
||||||
|
|
@ -1,154 +0,0 @@
|
||||||
// This is custom goose binary
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/pressly/goose"
|
|
||||||
|
|
||||||
pgusers "github.com/matrix-org/dendrite/userapi/storage/postgres/deltas"
|
|
||||||
slusers "github.com/matrix-org/dendrite/userapi/storage/sqlite3/deltas"
|
|
||||||
|
|
||||||
_ "github.com/lib/pq"
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
AppService = "appservice"
|
|
||||||
FederationSender = "federationapi"
|
|
||||||
KeyServer = "keyserver"
|
|
||||||
MediaAPI = "mediaapi"
|
|
||||||
RoomServer = "roomserver"
|
|
||||||
SigningKeyServer = "signingkeyserver"
|
|
||||||
SyncAPI = "syncapi"
|
|
||||||
UserAPI = "userapi"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
dir = flags.String("dir", "", "directory with migration files")
|
|
||||||
flags = flag.NewFlagSet("goose", flag.ExitOnError)
|
|
||||||
component = flags.String("component", "", "dendrite component name")
|
|
||||||
knownDBs = []string{
|
|
||||||
AppService, FederationSender, KeyServer, MediaAPI, RoomServer, SigningKeyServer, SyncAPI, UserAPI,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// nolint: gocyclo
|
|
||||||
func main() {
|
|
||||||
err := flags.Parse(os.Args[1:])
|
|
||||||
if err != nil {
|
|
||||||
panic(err.Error())
|
|
||||||
}
|
|
||||||
args := flags.Args()
|
|
||||||
|
|
||||||
if len(args) < 3 {
|
|
||||||
fmt.Println(
|
|
||||||
`Usage: goose [OPTIONS] DRIVER DBSTRING COMMAND
|
|
||||||
|
|
||||||
Drivers:
|
|
||||||
postgres
|
|
||||||
sqlite3
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
goose -component roomserver sqlite3 ./roomserver.db status
|
|
||||||
goose -component roomserver sqlite3 ./roomserver.db up
|
|
||||||
|
|
||||||
goose -component roomserver postgres "user=dendrite dbname=dendrite sslmode=disable" status
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-component string
|
|
||||||
Dendrite component name e.g roomserver, signingkeyserver, clientapi, syncapi
|
|
||||||
-table string
|
|
||||||
migrations table name (default "goose_db_version")
|
|
||||||
-h print help
|
|
||||||
-v enable verbose mode
|
|
||||||
-dir string
|
|
||||||
directory with migration files, only relevant when creating new migrations.
|
|
||||||
-version
|
|
||||||
print version
|
|
||||||
|
|
||||||
Commands:
|
|
||||||
up Migrate the DB to the most recent version available
|
|
||||||
up-by-one Migrate the DB up by 1
|
|
||||||
up-to VERSION Migrate the DB to a specific VERSION
|
|
||||||
down Roll back the version by 1
|
|
||||||
down-to VERSION Roll back to a specific VERSION
|
|
||||||
redo Re-run the latest migration
|
|
||||||
reset Roll back all migrations
|
|
||||||
status Dump the migration status for the current DB
|
|
||||||
version Print the current version of the database
|
|
||||||
create NAME [sql|go] Creates new migration file with the current timestamp
|
|
||||||
fix Apply sequential ordering to migrations`,
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
engine := args[0]
|
|
||||||
if engine != "sqlite3" && engine != "postgres" {
|
|
||||||
fmt.Println("engine must be one of 'sqlite3' or 'postgres'")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
knownComponent := false
|
|
||||||
for _, c := range knownDBs {
|
|
||||||
if c == *component {
|
|
||||||
knownComponent = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !knownComponent {
|
|
||||||
fmt.Printf("component must be one of %v\n", knownDBs)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if engine == "sqlite3" {
|
|
||||||
loadSQLiteDeltas(*component)
|
|
||||||
} else {
|
|
||||||
loadPostgresDeltas(*component)
|
|
||||||
}
|
|
||||||
|
|
||||||
dbstring, command := args[1], args[2]
|
|
||||||
|
|
||||||
db, err := goose.OpenDBWithDriver(engine, dbstring)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("goose: failed to open DB: %v\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err := db.Close(); err != nil {
|
|
||||||
log.Fatalf("goose: failed to close DB: %v\n", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
arguments := []string{}
|
|
||||||
if len(args) > 3 {
|
|
||||||
arguments = append(arguments, args[3:]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// goose demands a directory even though we don't use it for upgrades
|
|
||||||
d := *dir
|
|
||||||
if d == "" {
|
|
||||||
d = os.TempDir()
|
|
||||||
}
|
|
||||||
if err := goose.Run(command, db, d, arguments...); err != nil {
|
|
||||||
log.Fatalf("goose %v: %v", command, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadSQLiteDeltas(component string) {
|
|
||||||
switch component {
|
|
||||||
case UserAPI:
|
|
||||||
slusers.LoadFromGoose()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadPostgresDeltas(component string) {
|
|
||||||
switch component {
|
|
||||||
case UserAPI:
|
|
||||||
pgusers.LoadFromGoose()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal/caching"
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
"github.com/matrix-org/dendrite/roomserver/state"
|
"github.com/matrix-org/dendrite/roomserver/state"
|
||||||
|
|
@ -53,12 +54,10 @@ func main() {
|
||||||
|
|
||||||
fmt.Println("Fetching", len(snapshotNIDs), "snapshot NIDs")
|
fmt.Println("Fetching", len(snapshotNIDs), "snapshot NIDs")
|
||||||
|
|
||||||
cache, err := caching.NewInMemoryLRUCache(true)
|
roomserverDB, err := storage.Open(
|
||||||
if err != nil {
|
base, &cfg.RoomServer.Database,
|
||||||
panic(err)
|
caching.NewRistrettoCache(128*1024*1024, time.Hour, true),
|
||||||
}
|
)
|
||||||
|
|
||||||
roomserverDB, err := storage.Open(base, &cfg.RoomServer.Database, cache)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,33 @@ global:
|
||||||
max_idle_conns: 5
|
max_idle_conns: 5
|
||||||
conn_max_lifetime: -1
|
conn_max_lifetime: -1
|
||||||
|
|
||||||
|
# Configuration for in-memory caches. Caches can often improve performance by
|
||||||
|
# keeping frequently accessed items (like events, identifiers etc.) in memory
|
||||||
|
# rather than having to read them from the database.
|
||||||
|
cache:
|
||||||
|
# The estimated maximum size for the global cache in bytes, or in terabytes,
|
||||||
|
# gigabytes, megabytes or kilobytes when the appropriate 'tb', 'gb', 'mb' or
|
||||||
|
# 'kb' suffix is specified. Note that this is not a hard limit, nor is it a
|
||||||
|
# memory limit for the entire process. A cache that is too small may ultimately
|
||||||
|
# provide little or no benefit.
|
||||||
|
max_size_estimated: 1gb
|
||||||
|
|
||||||
|
# The maximum amount of time that a cache entry can live for in memory before
|
||||||
|
# it will be evicted and/or refreshed from the database. Lower values result in
|
||||||
|
# easier admission of new cache entries but may also increase database load in
|
||||||
|
# comparison to higher values, so adjust conservatively. Higher values may make
|
||||||
|
# it harder for new items to make it into the cache, e.g. if new rooms suddenly
|
||||||
|
# become popular.
|
||||||
|
max_age: 1h
|
||||||
|
|
||||||
# The server name to delegate server-server communications to, with optional port
|
# The server name to delegate server-server communications to, with optional port
|
||||||
# e.g. localhost:443
|
# e.g. localhost:443
|
||||||
well_known_server_name: ""
|
well_known_server_name: ""
|
||||||
|
|
||||||
|
# The server name to delegate client-server communications to, with optional port
|
||||||
|
# e.g. localhost:443
|
||||||
|
well_known_client_name: ""
|
||||||
|
|
||||||
# Lists of domains that the server will trust as identity servers to verify third
|
# Lists of domains that the server will trust as identity servers to verify third
|
||||||
# party identifiers such as phone numbers and email addresses.
|
# party identifiers such as phone numbers and email addresses.
|
||||||
trusted_third_party_id_servers:
|
trusted_third_party_id_servers:
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,33 @@ global:
|
||||||
# considered valid by other homeservers.
|
# considered valid by other homeservers.
|
||||||
key_validity_period: 168h0m0s
|
key_validity_period: 168h0m0s
|
||||||
|
|
||||||
|
# Configuration for in-memory caches. Caches can often improve performance by
|
||||||
|
# keeping frequently accessed items (like events, identifiers etc.) in memory
|
||||||
|
# rather than having to read them from the database.
|
||||||
|
cache:
|
||||||
|
# The estimated maximum size for the global cache in bytes, or in terabytes,
|
||||||
|
# gigabytes, megabytes or kilobytes when the appropriate 'tb', 'gb', 'mb' or
|
||||||
|
# 'kb' suffix is specified. Note that this is not a hard limit, nor is it a
|
||||||
|
# memory limit for the entire process. A cache that is too small may ultimately
|
||||||
|
# provide little or no benefit.
|
||||||
|
max_size_estimated: 1gb
|
||||||
|
|
||||||
|
# The maximum amount of time that a cache entry can live for in memory before
|
||||||
|
# it will be evicted and/or refreshed from the database. Lower values result in
|
||||||
|
# easier admission of new cache entries but may also increase database load in
|
||||||
|
# comparison to higher values, so adjust conservatively. Higher values may make
|
||||||
|
# it harder for new items to make it into the cache, e.g. if new rooms suddenly
|
||||||
|
# become popular.
|
||||||
|
max_age: 1h
|
||||||
|
|
||||||
# The server name to delegate server-server communications to, with optional port
|
# The server name to delegate server-server communications to, with optional port
|
||||||
# e.g. localhost:443
|
# e.g. localhost:443
|
||||||
well_known_server_name: ""
|
well_known_server_name: ""
|
||||||
|
|
||||||
|
# The server name to delegate client-server communications to, with optional port
|
||||||
|
# e.g. localhost:443
|
||||||
|
well_known_client_name: ""
|
||||||
|
|
||||||
# Lists of domains that the server will trust as identity servers to verify third
|
# Lists of domains that the server will trust as identity servers to verify third
|
||||||
# party identifiers such as phone numbers and email addresses.
|
# party identifiers such as phone numbers and email addresses.
|
||||||
trusted_third_party_id_servers:
|
trusted_third_party_id_servers:
|
||||||
|
|
@ -106,7 +129,7 @@ app_service_api:
|
||||||
|
|
||||||
# Database configuration for this component.
|
# Database configuration for this component.
|
||||||
database:
|
database:
|
||||||
connection_string: postgresql://username@password:hostname/dendrite_appservice?sslmode=disable
|
connection_string: postgresql://username:password@hostname/dendrite_appservice?sslmode=disable
|
||||||
max_open_conns: 10
|
max_open_conns: 10
|
||||||
max_idle_conns: 2
|
max_idle_conns: 2
|
||||||
conn_max_lifetime: -1
|
conn_max_lifetime: -1
|
||||||
|
|
@ -180,7 +203,7 @@ federation_api:
|
||||||
external_api:
|
external_api:
|
||||||
listen: http://[::]:8072
|
listen: http://[::]:8072
|
||||||
database:
|
database:
|
||||||
connection_string: postgresql://username@password:hostname/dendrite_federationapi?sslmode=disable
|
connection_string: postgresql://username:password@hostname/dendrite_federationapi?sslmode=disable
|
||||||
max_open_conns: 10
|
max_open_conns: 10
|
||||||
max_idle_conns: 2
|
max_idle_conns: 2
|
||||||
conn_max_lifetime: -1
|
conn_max_lifetime: -1
|
||||||
|
|
@ -217,7 +240,7 @@ key_server:
|
||||||
listen: http://[::]:7779 # The listen address for incoming API requests
|
listen: http://[::]:7779 # The listen address for incoming API requests
|
||||||
connect: http://key_server:7779 # The connect address for other components to use
|
connect: http://key_server:7779 # The connect address for other components to use
|
||||||
database:
|
database:
|
||||||
connection_string: postgresql://username@password:hostname/dendrite_keyserver?sslmode=disable
|
connection_string: postgresql://username:password@hostname/dendrite_keyserver?sslmode=disable
|
||||||
max_open_conns: 10
|
max_open_conns: 10
|
||||||
max_idle_conns: 2
|
max_idle_conns: 2
|
||||||
conn_max_lifetime: -1
|
conn_max_lifetime: -1
|
||||||
|
|
@ -230,7 +253,7 @@ media_api:
|
||||||
external_api:
|
external_api:
|
||||||
listen: http://[::]:8074
|
listen: http://[::]:8074
|
||||||
database:
|
database:
|
||||||
connection_string: postgresql://username@password:hostname/dendrite_mediaapi?sslmode=disable
|
connection_string: postgresql://username:password@hostname/dendrite_mediaapi?sslmode=disable
|
||||||
max_open_conns: 5
|
max_open_conns: 5
|
||||||
max_idle_conns: 2
|
max_idle_conns: 2
|
||||||
conn_max_lifetime: -1
|
conn_max_lifetime: -1
|
||||||
|
|
@ -267,7 +290,7 @@ mscs:
|
||||||
# - msc2836 # (Threading, see https://github.com/matrix-org/matrix-doc/pull/2836)
|
# - msc2836 # (Threading, see https://github.com/matrix-org/matrix-doc/pull/2836)
|
||||||
# - msc2946 # (Spaces Summary, see https://github.com/matrix-org/matrix-doc/pull/2946)
|
# - msc2946 # (Spaces Summary, see https://github.com/matrix-org/matrix-doc/pull/2946)
|
||||||
database:
|
database:
|
||||||
connection_string: postgresql://username@password:hostname/dendrite_mscs?sslmode=disable
|
connection_string: postgresql://username:password@hostname/dendrite_mscs?sslmode=disable
|
||||||
max_open_conns: 5
|
max_open_conns: 5
|
||||||
max_idle_conns: 2
|
max_idle_conns: 2
|
||||||
conn_max_lifetime: -1
|
conn_max_lifetime: -1
|
||||||
|
|
@ -278,7 +301,7 @@ room_server:
|
||||||
listen: http://[::]:7770 # The listen address for incoming API requests
|
listen: http://[::]:7770 # The listen address for incoming API requests
|
||||||
connect: http://room_server:7770 # The connect address for other components to use
|
connect: http://room_server:7770 # The connect address for other components to use
|
||||||
database:
|
database:
|
||||||
connection_string: postgresql://username@password:hostname/dendrite_roomserver?sslmode=disable
|
connection_string: postgresql://username:password@hostname/dendrite_roomserver?sslmode=disable
|
||||||
max_open_conns: 10
|
max_open_conns: 10
|
||||||
max_idle_conns: 2
|
max_idle_conns: 2
|
||||||
conn_max_lifetime: -1
|
conn_max_lifetime: -1
|
||||||
|
|
@ -291,7 +314,7 @@ sync_api:
|
||||||
external_api:
|
external_api:
|
||||||
listen: http://[::]:8073
|
listen: http://[::]:8073
|
||||||
database:
|
database:
|
||||||
connection_string: postgresql://username@password:hostname/dendrite_syncapi?sslmode=disable
|
connection_string: postgresql://username:password@hostname/dendrite_syncapi?sslmode=disable
|
||||||
max_open_conns: 10
|
max_open_conns: 10
|
||||||
max_idle_conns: 2
|
max_idle_conns: 2
|
||||||
conn_max_lifetime: -1
|
conn_max_lifetime: -1
|
||||||
|
|
@ -307,7 +330,7 @@ user_api:
|
||||||
listen: http://[::]:7781 # The listen address for incoming API requests
|
listen: http://[::]:7781 # The listen address for incoming API requests
|
||||||
connect: http://user_api:7781 # The connect address for other components to use
|
connect: http://user_api:7781 # The connect address for other components to use
|
||||||
account_database:
|
account_database:
|
||||||
connection_string: postgresql://username@password:hostname/dendrite_userapi?sslmode=disable
|
connection_string: postgresql://username:password@hostname/dendrite_userapi?sslmode=disable
|
||||||
max_open_conns: 10
|
max_open_conns: 10
|
||||||
max_idle_conns: 2
|
max_idle_conns: 2
|
||||||
conn_max_lifetime: -1
|
conn_max_lifetime: -1
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ Unfortunately we can't accept contributions without it.
|
||||||
|
|
||||||
## Getting up and running
|
## Getting up and running
|
||||||
|
|
||||||
See the [Installation](INSTALL.md) section for information on how to build an
|
See the [Installation](installation) section for information on how to build an
|
||||||
instance of Dendrite. You will likely need this in order to test your changes.
|
instance of Dendrite. You will likely need this in order to test your changes.
|
||||||
|
|
||||||
## Code style
|
## Code style
|
||||||
|
|
|
||||||
|
|
@ -86,9 +86,12 @@ would be a huge help too, as that will help us to understand where the memory us
|
||||||
|
|
||||||
You may need to revisit the connection limit of your PostgreSQL server and/or make changes to the `max_connections` lines in your Dendrite configuration. Be aware that each Dendrite component opens its own database connections and has its own connection limit, even in monolith mode!
|
You may need to revisit the connection limit of your PostgreSQL server and/or make changes to the `max_connections` lines in your Dendrite configuration. Be aware that each Dendrite component opens its own database connections and has its own connection limit, even in monolith mode!
|
||||||
|
|
||||||
## What is being reported when enabling anonymous stats?
|
## What is being reported when enabling phone-home statistics?
|
||||||
|
|
||||||
If anonymous stats reporting is enabled, the following data is send to the defined endpoint.
|
Phone-home statistics contain your server's domain name, some configuration information about
|
||||||
|
your deployment and aggregated information about active users on your deployment. They are sent
|
||||||
|
to the endpoint URL configured in your Dendrite configuration file only. The following is an
|
||||||
|
example of the data that is sent:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
@ -106,7 +109,7 @@ If anonymous stats reporting is enabled, the following data is send to the defin
|
||||||
"go_arch": "amd64",
|
"go_arch": "amd64",
|
||||||
"go_os": "linux",
|
"go_os": "linux",
|
||||||
"go_version": "go1.16.13",
|
"go_version": "go1.16.13",
|
||||||
"homeserver": "localhost:8800",
|
"homeserver": "my.domain.com",
|
||||||
"log_level": "trace",
|
"log_level": "trace",
|
||||||
"memory_rss": 93452,
|
"memory_rss": 93452,
|
||||||
"monolith": true,
|
"monolith": true,
|
||||||
|
|
|
||||||
|
|
@ -233,6 +233,8 @@ GEM
|
||||||
multipart-post (2.1.1)
|
multipart-post (2.1.1)
|
||||||
nokogiri (1.13.6-arm64-darwin)
|
nokogiri (1.13.6-arm64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
|
nokogiri (1.13.6-x86_64-linux)
|
||||||
|
racc (~> 1.4)
|
||||||
octokit (4.22.0)
|
octokit (4.22.0)
|
||||||
faraday (>= 0.9)
|
faraday (>= 0.9)
|
||||||
sawyer (~> 0.8.0, >= 0.5.3)
|
sawyer (~> 0.8.0, >= 0.5.3)
|
||||||
|
|
@ -263,7 +265,7 @@ GEM
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
typhoeus (1.4.0)
|
typhoeus (1.4.0)
|
||||||
ethon (>= 0.9.0)
|
ethon (>= 0.9.0)
|
||||||
tzinfo (1.2.9)
|
tzinfo (1.2.10)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
|
|
@ -273,11 +275,11 @@ GEM
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
arm64-darwin-21
|
arm64-darwin-21
|
||||||
|
x86_64-linux
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
github-pages (~> 226)
|
github-pages (~> 226)
|
||||||
jekyll-feed (~> 0.15.1)
|
jekyll-feed (~> 0.15.1)
|
||||||
minima (~> 2.5.1)
|
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.3.7
|
2.3.7
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,15 @@ To create a new **admin account**, add the `-admin` flag:
|
||||||
./bin/create-account -config /path/to/dendrite.yaml -username USERNAME -admin
|
./bin/create-account -config /path/to/dendrite.yaml -username USERNAME -admin
|
||||||
```
|
```
|
||||||
|
|
||||||
|
An example of using `create-account` when running in **Docker**, having found the `CONTAINERNAME` from `docker ps`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -it CONTAINERNAME /usr/bin/create-account -config /path/to/dendrite.yaml -username USERNAME
|
||||||
|
```
|
||||||
|
```bash
|
||||||
|
docker exec -it CONTAINERNAME /usr/bin/create-account -config /path/to/dendrite.yaml -username USERNAME -admin
|
||||||
|
```
|
||||||
|
|
||||||
## Using shared secret registration
|
## Using shared secret registration
|
||||||
|
|
||||||
Dendrite supports the Synapse-compatible shared secret registration endpoint.
|
Dendrite supports the Synapse-compatible shared secret registration endpoint.
|
||||||
|
|
|
||||||
81
docs/administration/5_troubleshooting.md
Normal file
81
docs/administration/5_troubleshooting.md
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
---
|
||||||
|
title: Troubleshooting
|
||||||
|
parent: Administration
|
||||||
|
permalink: /administration/troubleshooting
|
||||||
|
---
|
||||||
|
|
||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
If your Dendrite installation is acting strangely, there are a few things you should
|
||||||
|
check before seeking help.
|
||||||
|
|
||||||
|
## 1. Logs
|
||||||
|
|
||||||
|
Dendrite, by default, will log all warnings and errors to stdout, in addition to any
|
||||||
|
other locations configured in the `dendrite.yaml` configuration file. Often there will
|
||||||
|
be clues in the logs.
|
||||||
|
|
||||||
|
You can increase this log level to the more verbose `debug` level if necessary by adding
|
||||||
|
this to the config and restarting Dendrite:
|
||||||
|
|
||||||
|
```
|
||||||
|
logging:
|
||||||
|
- type: std
|
||||||
|
level: debug
|
||||||
|
```
|
||||||
|
|
||||||
|
Look specifically for lines that contain `level=error` or `level=warning`.
|
||||||
|
|
||||||
|
## 2. Federation tester
|
||||||
|
|
||||||
|
If you are experiencing problems federating with other homeservers, you should check
|
||||||
|
that the [Federation Tester](https://federationtester.matrix.org) is passing for your
|
||||||
|
server.
|
||||||
|
|
||||||
|
Common reasons that it may not pass include:
|
||||||
|
|
||||||
|
1. Incorrect DNS configuration;
|
||||||
|
2. Misconfigured DNS SRV entries or well-known files;
|
||||||
|
3. Invalid TLS/SSL certificates;
|
||||||
|
4. Reverse proxy configuration issues (if applicable).
|
||||||
|
|
||||||
|
Correct any errors if shown and re-run the federation tester to check the results.
|
||||||
|
|
||||||
|
## 3. System time
|
||||||
|
|
||||||
|
Matrix relies heavily on TLS which requires the system time to be correct. If the clock
|
||||||
|
drifts then you may find that federation no works reliably (or at all) and clients may
|
||||||
|
struggle to connect to your Dendrite server.
|
||||||
|
|
||||||
|
Ensure that your system time is correct and consider syncing to a reliable NTP source.
|
||||||
|
|
||||||
|
## 4. Database connections
|
||||||
|
|
||||||
|
If you are using the PostgreSQL database, you should ensure that Dendrite's configured
|
||||||
|
number of database connections does not exceed the maximum allowed by PostgreSQL.
|
||||||
|
|
||||||
|
Open your `postgresql.conf` configuration file and check the value of `max_connections`
|
||||||
|
(which is typically `100` by default). Then open your `dendrite.yaml` configuration file
|
||||||
|
and ensure that:
|
||||||
|
|
||||||
|
1. If you are using the `global.database` section, that `max_open_conns` does not exceed
|
||||||
|
that number;
|
||||||
|
2. If you are **not** using the `global.database` section, that the sum total of all
|
||||||
|
`max_open_conns` across all `database` blocks does not exceed that number.
|
||||||
|
|
||||||
|
## 5. File descriptors
|
||||||
|
|
||||||
|
Dendrite requires a sufficient number of file descriptors for every connection it makes
|
||||||
|
to a remote server, every connection to the database engine and every file it is reading
|
||||||
|
or writing to at a given time (media, logs etc). We recommend ensuring that the limit is
|
||||||
|
no lower than 65535 for Dendrite.
|
||||||
|
|
||||||
|
Dendrite will check at startup if there are a sufficient number of available descriptors.
|
||||||
|
If there aren't, you will see a log lines like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
level=warning msg="IMPORTANT: Process file descriptor limit is currently 65535, it is recommended to raise the limit for Dendrite to at least 65535 to avoid issues"
|
||||||
|
```
|
||||||
|
|
||||||
|
Follow the [Optimisation](../installation/10_optimisation.md) instructions to correct the
|
||||||
|
available number of file descriptors.
|
||||||
57
docs/caddy/monolith/Caddyfile
Normal file
57
docs/caddy/monolith/Caddyfile
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
# Sample Caddyfile for using Caddy in front of Dendrite.
|
||||||
|
#
|
||||||
|
# Customize email address and domain names.
|
||||||
|
# Optional settings commented out.
|
||||||
|
#
|
||||||
|
# BE SURE YOUR DOMAINS ARE POINTED AT YOUR SERVER FIRST.
|
||||||
|
# Documentation: https://caddyserver.com/docs/
|
||||||
|
#
|
||||||
|
# Bonus tip: If your IP address changes, use Caddy's
|
||||||
|
# dynamic DNS plugin to update your DNS records to
|
||||||
|
# point to your new IP automatically:
|
||||||
|
# https://github.com/mholt/caddy-dynamicdns
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# Global options block
|
||||||
|
{
|
||||||
|
# In case there is a problem with your certificates.
|
||||||
|
# email example@example.com
|
||||||
|
|
||||||
|
# Turn off the admin endpoint if you don't need graceful config
|
||||||
|
# changes and/or are running untrusted code on your machine.
|
||||||
|
# admin off
|
||||||
|
|
||||||
|
# Enable this if your clients don't send ServerName in TLS handshakes.
|
||||||
|
# default_sni example.com
|
||||||
|
|
||||||
|
# Enable debug mode for verbose logging.
|
||||||
|
# debug
|
||||||
|
|
||||||
|
# Use Let's Encrypt's staging endpoint for testing.
|
||||||
|
# acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
|
||||||
|
|
||||||
|
# If you're port-forwarding HTTP/HTTPS ports from 80/443 to something
|
||||||
|
# else, enable these and put the alternate port numbers here.
|
||||||
|
# http_port 8080
|
||||||
|
# https_port 8443
|
||||||
|
}
|
||||||
|
|
||||||
|
# The server name of your matrix homeserver. This example shows
|
||||||
|
# "well-known delegation" from the registered domain to a subdomain,
|
||||||
|
# which is only needed if your server_name doesn't match your Matrix
|
||||||
|
# homeserver URL (i.e. you can show users a vanity domain that looks
|
||||||
|
# nice and is easy to remember but still have your Matrix server on
|
||||||
|
# its own subdomain or hosted service).
|
||||||
|
example.com {
|
||||||
|
header /.well-known/matrix/* Content-Type application/json
|
||||||
|
header /.well-known/matrix/* Access-Control-Allow-Origin *
|
||||||
|
respond /.well-known/matrix/server `{"m.server": "matrix.example.com:443"}`
|
||||||
|
respond /.well-known/matrix/client `{"m.homeserver": {"base_url": "https://matrix.example.com"}}`
|
||||||
|
}
|
||||||
|
|
||||||
|
# The actual domain name whereby your Matrix server is accessed.
|
||||||
|
matrix.example.com {
|
||||||
|
# Set localhost:8008 to the address of your Dendrite server, if different
|
||||||
|
reverse_proxy /_matrix/* localhost:8008
|
||||||
|
}
|
||||||
66
docs/caddy/polylith/Caddyfile
Normal file
66
docs/caddy/polylith/Caddyfile
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
# Sample Caddyfile for using Caddy in front of Dendrite.
|
||||||
|
#
|
||||||
|
# Customize email address and domain names.
|
||||||
|
# Optional settings commented out.
|
||||||
|
#
|
||||||
|
# BE SURE YOUR DOMAINS ARE POINTED AT YOUR SERVER FIRST.
|
||||||
|
# Documentation: https://caddyserver.com/docs/
|
||||||
|
#
|
||||||
|
# Bonus tip: If your IP address changes, use Caddy's
|
||||||
|
# dynamic DNS plugin to update your DNS records to
|
||||||
|
# point to your new IP automatically:
|
||||||
|
# https://github.com/mholt/caddy-dynamicdns
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# Global options block
|
||||||
|
{
|
||||||
|
# In case there is a problem with your certificates.
|
||||||
|
# email example@example.com
|
||||||
|
|
||||||
|
# Turn off the admin endpoint if you don't need graceful config
|
||||||
|
# changes and/or are running untrusted code on your machine.
|
||||||
|
# admin off
|
||||||
|
|
||||||
|
# Enable this if your clients don't send ServerName in TLS handshakes.
|
||||||
|
# default_sni example.com
|
||||||
|
|
||||||
|
# Enable debug mode for verbose logging.
|
||||||
|
# debug
|
||||||
|
|
||||||
|
# Use Let's Encrypt's staging endpoint for testing.
|
||||||
|
# acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
|
||||||
|
|
||||||
|
# If you're port-forwarding HTTP/HTTPS ports from 80/443 to something
|
||||||
|
# else, enable these and put the alternate port numbers here.
|
||||||
|
# http_port 8080
|
||||||
|
# https_port 8443
|
||||||
|
}
|
||||||
|
|
||||||
|
# The server name of your matrix homeserver. This example shows
|
||||||
|
# "well-known delegation" from the registered domain to a subdomain,
|
||||||
|
# which is only needed if your server_name doesn't match your Matrix
|
||||||
|
# homeserver URL (i.e. you can show users a vanity domain that looks
|
||||||
|
# nice and is easy to remember but still have your Matrix server on
|
||||||
|
# its own subdomain or hosted service).
|
||||||
|
example.com {
|
||||||
|
header /.well-known/matrix/* Content-Type application/json
|
||||||
|
header /.well-known/matrix/* Access-Control-Allow-Origin *
|
||||||
|
respond /.well-known/matrix/server `{"m.server": "matrix.example.com:443"}`
|
||||||
|
respond /.well-known/matrix/client `{"m.homeserver": {"base_url": "https://matrix.example.com"}}`
|
||||||
|
}
|
||||||
|
|
||||||
|
# The actual domain name whereby your Matrix server is accessed.
|
||||||
|
matrix.example.com {
|
||||||
|
# Change the end of each reverse_proxy line to the correct
|
||||||
|
# address for your various services.
|
||||||
|
@sync_api {
|
||||||
|
path_regexp /_matrix/client/.*?/(sync|user/.*?/filter/?.*|keys/changes|rooms/.*?/messages)$
|
||||||
|
}
|
||||||
|
reverse_proxy @sync_api sync_api:8073
|
||||||
|
|
||||||
|
reverse_proxy /_matrix/client* client_api:8071
|
||||||
|
reverse_proxy /_matrix/federation* federation_api:8071
|
||||||
|
reverse_proxy /_matrix/key* federation_api:8071
|
||||||
|
reverse_proxy /_matrix/media* media_api:8071
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
title: Starting the polylith
|
title: Starting the polylith
|
||||||
parent: Installation
|
parent: Installation
|
||||||
has_toc: true
|
has_toc: true
|
||||||
nav_order: 9
|
nav_order: 10
|
||||||
permalink: /installation/start/polylith
|
permalink: /installation/start/polylith
|
||||||
---
|
---
|
||||||
|
|
||||||
71
docs/installation/11_optimisation.md
Normal file
71
docs/installation/11_optimisation.md
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
---
|
||||||
|
title: Optimise your installation
|
||||||
|
parent: Installation
|
||||||
|
has_toc: true
|
||||||
|
nav_order: 11
|
||||||
|
permalink: /installation/start/optimisation
|
||||||
|
---
|
||||||
|
|
||||||
|
# Optimise your installation
|
||||||
|
|
||||||
|
Now that you have Dendrite running, the following tweaks will improve the reliability
|
||||||
|
and performance of your installation.
|
||||||
|
|
||||||
|
## File descriptor limit
|
||||||
|
|
||||||
|
Most platforms have a limit on how many file descriptors a single process can open. All
|
||||||
|
connections made by Dendrite consume file descriptors — this includes database connections
|
||||||
|
and network requests to remote homeservers. When participating in large federated rooms
|
||||||
|
where Dendrite must talk to many remote servers, it is often very easy to exhaust default
|
||||||
|
limits which are quite low.
|
||||||
|
|
||||||
|
We currently recommend setting the file descriptor limit to 65535 to avoid such
|
||||||
|
issues. Dendrite will log immediately after startup if the file descriptor limit is too low:
|
||||||
|
|
||||||
|
```
|
||||||
|
level=warning msg="IMPORTANT: Process file descriptor limit is currently 1024, it is recommended to raise the limit for Dendrite to at least 65535 to avoid issues"
|
||||||
|
```
|
||||||
|
|
||||||
|
UNIX systems have two limits: a hard limit and a soft limit. You can view the soft limit
|
||||||
|
by running `ulimit -Sn` and the hard limit with `ulimit -Hn`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ ulimit -Hn
|
||||||
|
1048576
|
||||||
|
|
||||||
|
$ ulimit -Sn
|
||||||
|
1024
|
||||||
|
```
|
||||||
|
|
||||||
|
Increase the soft limit before starting Dendrite:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ulimit -Sn 65535
|
||||||
|
```
|
||||||
|
|
||||||
|
The log line at startup should no longer appear if the limit is sufficient.
|
||||||
|
|
||||||
|
If you are running under a systemd service, you can instead add `LimitNOFILE=65535` option
|
||||||
|
to the `[Service]` section of your service unit file.
|
||||||
|
|
||||||
|
## DNS caching
|
||||||
|
|
||||||
|
Dendrite has a built-in DNS cache which significantly reduces the load that Dendrite will
|
||||||
|
place on your DNS resolver. This may also speed up outbound federation.
|
||||||
|
|
||||||
|
Consider enabling the DNS cache by modifying the `global` section of your configuration file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
dns_cache:
|
||||||
|
enabled: true
|
||||||
|
cache_size: 4096
|
||||||
|
cache_lifetime: 600s
|
||||||
|
```
|
||||||
|
|
||||||
|
## Time synchronisation
|
||||||
|
|
||||||
|
Matrix relies heavily on TLS which requires the system time to be correct. If the clock
|
||||||
|
drifts then you may find that federation no works reliably (or at all) and clients may
|
||||||
|
struggle to connect to your Dendrite server.
|
||||||
|
|
||||||
|
Ensure that the time is synchronised on your system by enabling NTP sync.
|
||||||
|
|
@ -75,7 +75,7 @@ In order to install Dendrite, you will need to satisfy the following dependencie
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
|
|
||||||
At this time, Dendrite supports being built with Go 1.16 or later. We do not support building
|
At this time, Dendrite supports being built with Go 1.18 or later. We do not support building
|
||||||
Dendrite with older versions of Go than this. If you are installing Go using a package manager,
|
Dendrite with older versions of Go than this. If you are installing Go using a package manager,
|
||||||
you should check (by running `go version`) that you are using a suitable version before you start.
|
you should check (by running `go version`) that you are using a suitable version before you start.
|
||||||
|
|
||||||
|
|
@ -95,12 +95,13 @@ enabled.
|
||||||
To do so, follow the [NATS Server installation instructions](https://docs.nats.io/running-a-nats-service/introduction/installation) and then [start your NATS deployment](https://docs.nats.io/running-a-nats-service/introduction/running). JetStream must be enabled, either by passing the `-js` flag to `nats-server`,
|
To do so, follow the [NATS Server installation instructions](https://docs.nats.io/running-a-nats-service/introduction/installation) and then [start your NATS deployment](https://docs.nats.io/running-a-nats-service/introduction/running). JetStream must be enabled, either by passing the `-js` flag to `nats-server`,
|
||||||
or by specifying the `store_dir` option in the the `jetstream` configuration.
|
or by specifying the `store_dir` option in the the `jetstream` configuration.
|
||||||
|
|
||||||
### Reverse proxy (polylith deployments)
|
### Reverse proxy
|
||||||
|
|
||||||
Polylith deployments require a reverse proxy, such as [NGINX](https://www.nginx.com) or
|
A reverse proxy such as [Caddy](https://caddyserver.com), [NGINX](https://www.nginx.com) or
|
||||||
[HAProxy](http://www.haproxy.org). Configuring those is not covered in this documentation,
|
[HAProxy](http://www.haproxy.org) is required for polylith deployments and is useful for monolith
|
||||||
although a [sample configuration for NGINX](https://github.com/matrix-org/dendrite/blob/main/docs/nginx/polylith-sample.conf)
|
deployments. Configuring those is not covered in this documentation, although sample configurations
|
||||||
is provided.
|
for [Caddy](https://github.com/matrix-org/dendrite/blob/main/docs/caddy) and
|
||||||
|
[NGINX](https://github.com/matrix-org/dendrite/blob/main/docs/nginx) are provided.
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,27 +14,38 @@ that take the format `@user:example.com`.
|
||||||
For federation to work, the server name must be resolvable by other homeservers on the internet
|
For federation to work, the server name must be resolvable by other homeservers on the internet
|
||||||
— that is, the domain must be registered and properly configured with the relevant DNS records.
|
— that is, the domain must be registered and properly configured with the relevant DNS records.
|
||||||
|
|
||||||
Matrix servers discover each other when federating using the following methods:
|
Matrix servers usually discover each other when federating using the following methods:
|
||||||
|
|
||||||
1. If a well-known delegation exists on `example.com`, use the path server from the
|
1. If a well-known delegation exists on `example.com`, use the domain and port from the
|
||||||
well-known file to connect to the remote homeserver;
|
well-known file to connect to the remote homeserver;
|
||||||
2. If a DNS SRV delegation exists on `example.com`, use the hostname and port from the DNS SRV
|
2. If a DNS SRV delegation exists on `example.com`, use the IP address and port from the DNS SRV
|
||||||
record to connect to the remote homeserver;
|
record to connect to the remote homeserver;
|
||||||
3. If neither well-known or DNS SRV delegation are configured, attempt to connect to the remote
|
3. If neither well-known or DNS SRV delegation are configured, attempt to connect to the remote
|
||||||
homeserver by connecting to `example.com` port TCP/8448 using HTTPS.
|
homeserver by connecting to `example.com` port TCP/8448 using HTTPS.
|
||||||
|
|
||||||
|
The exact details of how server name resolution works can be found in
|
||||||
|
[the spec](https://spec.matrix.org/v1.3/server-server-api/#resolving-server-names).
|
||||||
|
|
||||||
## TLS certificates
|
## TLS certificates
|
||||||
|
|
||||||
Matrix federation requires that valid TLS certificates are present on the domain. You must
|
Matrix federation requires that valid TLS certificates are present on the domain. You must
|
||||||
obtain certificates from a publicly accepted Certificate Authority (CA). [LetsEncrypt](https://letsencrypt.org)
|
obtain certificates from a publicly-trusted certificate authority (CA). [Let's Encrypt](https://letsencrypt.org)
|
||||||
is an example of such a CA that can be used. Self-signed certificates are not suitable for
|
is a popular choice of CA because the certificates are publicly-trusted, free, and automated
|
||||||
federation and will typically not be accepted by other homeservers.
|
via the ACME protocol. (Self-signed certificates are not suitable for federation and will typically
|
||||||
|
not be accepted by other homeservers.)
|
||||||
|
|
||||||
A common practice to help ease the management of certificates is to install a reverse proxy in
|
Automating the renewal of TLS certificates is best practice. There are many tools for this,
|
||||||
front of Dendrite which manages the TLS certificates and HTTPS proxying itself. Software such as
|
but the simplest way to achieve TLS automation is to have your reverse proxy do it for you.
|
||||||
[NGINX](https://www.nginx.com) and [HAProxy](http://www.haproxy.org) can be used for the task.
|
[Caddy](https://caddyserver.com) is recommended as a production-grade reverse proxy with
|
||||||
Although the finer details of configuring these are not described here, you must reverse proxy
|
automatic TLS which is commonly used in front of Dendrite. It obtains and renews TLS certificates
|
||||||
all `/_matrix` paths to your Dendrite server.
|
automatically and by default as long as your domain name is pointed at your server first.
|
||||||
|
Although the finer details of [configuring Caddy](https://caddyserver.com/docs/) is not described
|
||||||
|
here, in general, you must reverse proxy all `/_matrix` paths to your Dendrite server. For example,
|
||||||
|
with Caddy:
|
||||||
|
|
||||||
|
```
|
||||||
|
reverse_proxy /_matrix/* localhost:8008
|
||||||
|
```
|
||||||
|
|
||||||
It is possible for the reverse proxy to listen on the standard HTTPS port TCP/443 so long as your
|
It is possible for the reverse proxy to listen on the standard HTTPS port TCP/443 so long as your
|
||||||
domain delegation is configured to point to port TCP/443.
|
domain delegation is configured to point to port TCP/443.
|
||||||
|
|
@ -51,17 +62,12 @@ you will be able to delegate from `example.com` to `matrix.example.com` so that
|
||||||
|
|
||||||
Delegation can be performed in one of two ways:
|
Delegation can be performed in one of two ways:
|
||||||
|
|
||||||
* **Well-known delegation**: A well-known text file is served over HTTPS on the domain name
|
* **Well-known delegation (preferred)**: A well-known text file is served over HTTPS on the domain
|
||||||
that you want to use, pointing to your server on `matrix.example.com` port 8448;
|
name that you want to use, pointing to your server on `matrix.example.com` port 8448;
|
||||||
* **DNS SRV delegation**: A DNS SRV record is created on the domain name that you want to
|
* **DNS SRV delegation (not recommended)**: See the SRV delegation section below for details.
|
||||||
use, pointing to your server on `matrix.example.com` port TCP/8448.
|
|
||||||
|
|
||||||
If you are using a reverse proxy to forward `/_matrix` to Dendrite, your well-known or DNS SRV
|
If you are using a reverse proxy to forward `/_matrix` to Dendrite, your well-known or delegation
|
||||||
delegation must refer to the hostname and port that the reverse proxy is listening on instead.
|
must refer to the hostname and port that the reverse proxy is listening on instead.
|
||||||
|
|
||||||
Well-known delegation is typically easier to set up and usually preferred. However, you can use
|
|
||||||
either or both methods to delegate. If you configure both methods of delegation, it is important
|
|
||||||
that they both agree and refer to the same hostname and port.
|
|
||||||
|
|
||||||
## Well-known delegation
|
## Well-known delegation
|
||||||
|
|
||||||
|
|
@ -74,20 +80,46 @@ and contain the following JSON document:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"m.server": "https://matrix.example.com:8448"
|
"m.server": "matrix.example.com:8448"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For example, this can be done with the following Caddy config:
|
||||||
|
|
||||||
|
```
|
||||||
|
handle /.well-known/matrix/client {
|
||||||
|
header Content-Type application/json
|
||||||
|
header Access-Control-Allow-Origin *
|
||||||
|
respond `{"m.homeserver": {"base_url": "https://matrix.example.com:8448"}}`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also serve `.well-known` with Dendrite itself by setting the `well_known_server_name` config
|
||||||
|
option to the value you want for `m.server`. This is primarily useful if Dendrite is exposed on
|
||||||
|
`example.com:443` and you don't want to set up a separate webserver just for serving the `.well-known`
|
||||||
|
file.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
global:
|
||||||
|
...
|
||||||
|
well_known_server_name: "example.com:443"
|
||||||
|
```
|
||||||
|
|
||||||
## DNS SRV delegation
|
## DNS SRV delegation
|
||||||
|
|
||||||
Using DNS SRV delegation requires creating DNS SRV records on the `example.com` zone which
|
This method is not recommended, as the behavior of SRV records in Matrix is rather unintuitive:
|
||||||
refer to your Dendrite installation.
|
SRV records will only change the IP address and port that other servers connect to, they won't
|
||||||
|
affect the domain name. In technical terms, the `Host` header and TLS SNI of federation requests
|
||||||
|
will still be `example.com` even if the SRV record points at `matrix.example.com`.
|
||||||
|
|
||||||
Assuming that your Dendrite installation is listening for HTTPS connections at `matrix.example.com`
|
In practice, this means that the server must be configured with valid TLS certificates for
|
||||||
port 8448, the DNS SRV record must have the following fields:
|
`example.com`, rather than `matrix.example.com` as one might intuitively expect. If there's a
|
||||||
|
reverse proxy in between, the proxy configuration must be written as if it's `example.com`, as the
|
||||||
|
proxy will never see the name `matrix.example.com` in incoming requests.
|
||||||
|
|
||||||
* Name: `@` (or whichever term your DNS provider uses to signal the root)
|
This behavior also means that if `example.com` and `matrix.example.com` point at the same IP
|
||||||
* Service: `_matrix`
|
address, there is no reason to have a SRV record pointing at `matrix.example.com`. It can still
|
||||||
* Protocol: `_tcp`
|
be used to change the port number, but it won't do anything else.
|
||||||
* Port: `8448`
|
|
||||||
* Target: `matrix.example.com`
|
If you understand how SRV records work and still want to use them, the service name is `_matrix` and
|
||||||
|
the protocol is `_tcp`.
|
||||||
|
|
|
||||||
38
docs/installation/3_build.md
Normal file
38
docs/installation/3_build.md
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
---
|
||||||
|
title: Building Dendrite
|
||||||
|
parent: Installation
|
||||||
|
has_toc: true
|
||||||
|
nav_order: 3
|
||||||
|
permalink: /installation/build
|
||||||
|
---
|
||||||
|
|
||||||
|
# Build all Dendrite commands
|
||||||
|
|
||||||
|
Dendrite has numerous utility commands in addition to the actual server binaries.
|
||||||
|
Build them all from the root of the source repo with `build.sh` (Linux/Mac):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
or `build.cmd` (Windows):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
build.cmd
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting binaries will be placed in the `bin` subfolder.
|
||||||
|
|
||||||
|
# Installing as a monolith
|
||||||
|
|
||||||
|
You can install the Dendrite monolith binary into `$GOPATH/bin` by using `go install`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go install ./cmd/dendrite-monolith-server
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can specify a custom path for the binary to be written to using `go build`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go build -o /usr/local/bin/ ./cmd/dendrite-monolith-server
|
||||||
|
```
|
||||||
|
|
@ -17,7 +17,9 @@ filenames in the Dendrite configuration file and start Dendrite. The databases w
|
||||||
and populated automatically.
|
and populated automatically.
|
||||||
|
|
||||||
Note that Dendrite **cannot share a single SQLite database across multiple components**. Each
|
Note that Dendrite **cannot share a single SQLite database across multiple components**. Each
|
||||||
component must be configured with its own SQLite database filename.
|
component must be configured with its own SQLite database filename. You will have to remove
|
||||||
|
the `global.database` section from your Dendrite config and add it to each individual section
|
||||||
|
instead in order to use SQLite.
|
||||||
|
|
||||||
### Connection strings
|
### Connection strings
|
||||||
|
|
||||||
|
|
@ -29,5 +29,6 @@ Polylith deployments require a reverse proxy in order to ensure that requests ar
|
||||||
sent to the correct endpoint. You must ensure that a suitable reverse proxy is installed
|
sent to the correct endpoint. You must ensure that a suitable reverse proxy is installed
|
||||||
and configured.
|
and configured.
|
||||||
|
|
||||||
A [sample configuration file](https://github.com/matrix-org/dendrite/blob/main/docs/nginx/polylith-sample.conf)
|
Sample configurations are provided
|
||||||
is provided for [NGINX](https://www.nginx.com).
|
for [Caddy](https://github.com/matrix-org/dendrite/blob/main/docs/caddy/polylith/Caddyfile)
|
||||||
|
and [NGINX](https://github.com/matrix-org/dendrite/blob/main/docs/nginx/polylith-sample.conf).
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
---
|
---
|
||||||
title: Populate the configuration
|
title: Configuring Dendrite
|
||||||
parent: Installation
|
parent: Installation
|
||||||
nav_order: 7
|
nav_order: 7
|
||||||
permalink: /installation/configuration
|
permalink: /installation/configuration
|
||||||
---
|
---
|
||||||
|
|
||||||
# Populate the configuration
|
# Configuring Dendrite
|
||||||
|
|
||||||
The configuration file is used to configure Dendrite. Sample configuration files are
|
A YAML configuration file is used to configure Dendrite. Sample configuration files are
|
||||||
present in the top level of the Dendrite repository:
|
present in the top level of the Dendrite repository:
|
||||||
|
|
||||||
* [`dendrite-sample.monolith.yaml`](https://github.com/matrix-org/dendrite/blob/main/dendrite-sample.monolith.yaml)
|
* [`dendrite-sample.monolith.yaml`](https://github.com/matrix-org/dendrite/blob/main/dendrite-sample.monolith.yaml)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
title: Generating signing keys
|
title: Generating signing keys
|
||||||
parent: Installation
|
parent: Installation
|
||||||
nav_order: 4
|
nav_order: 8
|
||||||
permalink: /installation/signingkeys
|
permalink: /installation/signingkeys
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -15,8 +15,9 @@ you can start your Dendrite monolith deployment by starting the `dendrite-monoli
|
||||||
./dendrite-monolith-server -config /path/to/dendrite.yaml
|
./dendrite-monolith-server -config /path/to/dendrite.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want to change the addresses or ports that Dendrite listens on, you
|
By default, Dendrite will listen HTTP on port 8008. If you want to change the addresses
|
||||||
can use the `-http-bind-address` and `-https-bind-address` command line arguments:
|
or ports that Dendrite listens on, you can use the `-http-bind-address` and
|
||||||
|
`-https-bind-address` command line arguments:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./dendrite-monolith-server -config /path/to/dendrite.yaml \
|
./dendrite-monolith-server -config /path/to/dendrite.yaml \
|
||||||
|
|
@ -90,7 +90,7 @@ func (t *OutputReceiptConsumer) onMessage(ctx context.Context, msg *nats.Msg) bo
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp, err := strconv.Atoi(msg.Header.Get("timestamp"))
|
timestamp, err := strconv.ParseUint(msg.Header.Get("timestamp"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If the message was invalid, log it and move on to the next message in the stream
|
// If the message was invalid, log it and move on to the next message in the stream
|
||||||
log.WithError(err).Errorf("EDU output log: message parse failure")
|
log.WithError(err).Errorf("EDU output log: message parse failure")
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,11 @@ func (t *OutputSendToDeviceConsumer) onMessage(ctx context.Context, msg *nats.Ms
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The SyncAPI is already handling sendToDevice for the local server
|
||||||
|
if destServerName == t.ServerName {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Pack the EDU and marshal it
|
// Pack the EDU and marshal it
|
||||||
edu := &gomatrixserverlib.EDU{
|
edu := &gomatrixserverlib.EDU{
|
||||||
Type: gomatrixserverlib.MDirectToDevice,
|
Type: gomatrixserverlib.MDirectToDevice,
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -64,10 +63,7 @@ func TestMain(m *testing.M) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new cache but don't enable prometheus!
|
// Create a new cache but don't enable prometheus!
|
||||||
s.cache, err = caching.NewInMemoryLRUCache(false)
|
s.cache = caching.NewRistrettoCache(8*1024*1024, time.Hour, false)
|
||||||
if err != nil {
|
|
||||||
panic("can't create cache: " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a temporary directory for JetStream.
|
// Create a temporary directory for JetStream.
|
||||||
d, err := ioutil.TempDir("./", "jetstream*")
|
d, err := ioutil.TempDir("./", "jetstream*")
|
||||||
|
|
@ -170,72 +166,6 @@ func TestServersRequestOwnKeys(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCachingBehaviour(t *testing.T) {
|
|
||||||
// Server A will request Server B's key, which has a validity
|
|
||||||
// period of an hour from now. We should retrieve the key and
|
|
||||||
// it should make it into the cache automatically.
|
|
||||||
|
|
||||||
req := gomatrixserverlib.PublicKeyLookupRequest{
|
|
||||||
ServerName: serverB.name,
|
|
||||||
KeyID: serverKeyID,
|
|
||||||
}
|
|
||||||
ts := gomatrixserverlib.AsTimestamp(time.Now())
|
|
||||||
|
|
||||||
res, err := serverA.api.FetchKeys(
|
|
||||||
context.Background(),
|
|
||||||
map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp{
|
|
||||||
req: ts,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("server A failed to retrieve server B key: %s", err)
|
|
||||||
}
|
|
||||||
if len(res) != 1 {
|
|
||||||
t.Fatalf("server B should have returned one key but instead returned %d keys", len(res))
|
|
||||||
}
|
|
||||||
if _, ok := res[req]; !ok {
|
|
||||||
t.Fatalf("server B isn't included in the key fetch response")
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point, if the previous key request was a success,
|
|
||||||
// then the cache should now contain the key. Check if that's
|
|
||||||
// the case - if it isn't then there's something wrong with
|
|
||||||
// the cache implementation or we failed to get the key.
|
|
||||||
|
|
||||||
cres, ok := serverA.cache.GetServerKey(req, ts)
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("server B key should be in cache but isn't")
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(cres, res[req]) {
|
|
||||||
t.Fatalf("the cached result from server B wasn't what server B gave us")
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we ask the cache for the same key but this time for an event
|
|
||||||
// that happened in +30 minutes. Since the validity period is for
|
|
||||||
// another hour, then we should get a response back from the cache.
|
|
||||||
|
|
||||||
_, ok = serverA.cache.GetServerKey(
|
|
||||||
req,
|
|
||||||
gomatrixserverlib.AsTimestamp(time.Now().Add(time.Minute*30)),
|
|
||||||
)
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("server B key isn't in cache when it should be (+30 minutes)")
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we ask the cache for the same key but this time for an event
|
|
||||||
// that happened in +90 minutes then we should expect to get no
|
|
||||||
// cache result. This is because the cache shouldn't return a result
|
|
||||||
// that is obviously past the validity of the event.
|
|
||||||
|
|
||||||
_, ok = serverA.cache.GetServerKey(
|
|
||||||
req,
|
|
||||||
gomatrixserverlib.AsTimestamp(time.Now().Add(time.Minute*90)),
|
|
||||||
)
|
|
||||||
if ok {
|
|
||||||
t.Fatalf("server B key is in cache when it shouldn't be (+90 minutes)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRenewalBehaviour(t *testing.T) {
|
func TestRenewalBehaviour(t *testing.T) {
|
||||||
// Server A will request Server C's key but their validity period
|
// Server A will request Server C's key but their validity period
|
||||||
// is an hour in the past. We'll retrieve the key as, even though it's
|
// is an hour in the past. We'll retrieve the key as, even though it's
|
||||||
|
|
@ -262,32 +192,7 @@ func TestRenewalBehaviour(t *testing.T) {
|
||||||
t.Fatalf("server C isn't included in the key fetch response")
|
t.Fatalf("server C isn't included in the key fetch response")
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we ask the cache for the server key for an event that happened
|
originalValidity := res[req].ValidUntilTS
|
||||||
// 90 minutes ago then we should get a cache result, as the key hadn't
|
|
||||||
// passed its validity by that point. The fact that the key is now in
|
|
||||||
// the cache is, in itself, proof that we successfully retrieved the
|
|
||||||
// key before.
|
|
||||||
|
|
||||||
oldcached, ok := serverA.cache.GetServerKey(
|
|
||||||
req,
|
|
||||||
gomatrixserverlib.AsTimestamp(time.Now().Add(-time.Minute*90)),
|
|
||||||
)
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("server C key isn't in cache when it should be (-90 minutes)")
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we now ask the cache for the same key but this time for an event
|
|
||||||
// that only happened 30 minutes ago then we shouldn't get a cached
|
|
||||||
// result, as the event happened after the key validity expired. This
|
|
||||||
// is really just for sanity checking.
|
|
||||||
|
|
||||||
_, ok = serverA.cache.GetServerKey(
|
|
||||||
req,
|
|
||||||
gomatrixserverlib.AsTimestamp(time.Now().Add(-time.Minute*30)),
|
|
||||||
)
|
|
||||||
if ok {
|
|
||||||
t.Fatalf("server B key is in cache when it shouldn't be (-30 minutes)")
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're now going to kick server C into renewing its key. Since we're
|
// We're now going to kick server C into renewing its key. Since we're
|
||||||
// happy at this point that the key that we already have is from the past
|
// happy at this point that the key that we already have is from the past
|
||||||
|
|
@ -308,24 +213,13 @@ func TestRenewalBehaviour(t *testing.T) {
|
||||||
if len(res) != 1 {
|
if len(res) != 1 {
|
||||||
t.Fatalf("server C should have returned one key but instead returned %d keys", len(res))
|
t.Fatalf("server C should have returned one key but instead returned %d keys", len(res))
|
||||||
}
|
}
|
||||||
if _, ok = res[req]; !ok {
|
if _, ok := res[req]; !ok {
|
||||||
t.Fatalf("server C isn't included in the key fetch response")
|
t.Fatalf("server C isn't included in the key fetch response")
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're now going to ask the cache what the new key validity is. If
|
currentValidity := res[req].ValidUntilTS
|
||||||
// it is still the same as the previous validity then we've failed to
|
|
||||||
// retrieve the renewed key. If it's newer then we've successfully got
|
|
||||||
// the renewed key.
|
|
||||||
|
|
||||||
newcached, ok := serverA.cache.GetServerKey(
|
if originalValidity == currentValidity {
|
||||||
req,
|
t.Fatalf("server C key should have renewed but didn't")
|
||||||
gomatrixserverlib.AsTimestamp(time.Now().Add(-time.Minute*30)),
|
|
||||||
)
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("server B key isn't in cache when it shouldn't be (post-renewal)")
|
|
||||||
}
|
}
|
||||||
if oldcached.ValidUntilTS >= newcached.ValidUntilTS {
|
|
||||||
t.Fatalf("the server B key should have been renewed but wasn't")
|
|
||||||
}
|
|
||||||
t.Log(res)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ func (p *SyncAPIProducer) SendReceipt(
|
||||||
m.Header.Set(jetstream.RoomID, roomID)
|
m.Header.Set(jetstream.RoomID, roomID)
|
||||||
m.Header.Set(jetstream.EventID, eventID)
|
m.Header.Set(jetstream.EventID, eventID)
|
||||||
m.Header.Set("type", receiptType)
|
m.Header.Set("type", receiptType)
|
||||||
m.Header.Set("timestamp", strconv.Itoa(int(timestamp)))
|
m.Header.Set("timestamp", fmt.Sprintf("%d", timestamp))
|
||||||
|
|
||||||
log.WithFields(log.Fields{}).Tracef("Producing to topic '%s'", p.TopicReceiptEvent)
|
log.WithFields(log.Fields{}).Tracef("Producing to topic '%s'", p.TopicReceiptEvent)
|
||||||
_, err := p.JetStream.PublishMsg(m, nats.Context(ctx))
|
_, err := p.JetStream.PublishMsg(m, nats.Context(ctx))
|
||||||
|
|
|
||||||
|
|
@ -141,10 +141,16 @@ func processInvite(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the event is signed by the server sending the request.
|
// Check that the event is signed by the server sending the request.
|
||||||
redacted := event.Redact()
|
redacted, err := gomatrixserverlib.RedactEventJSON(event.JSON(), event.Version())
|
||||||
|
if err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: jsonerror.BadJSON("The event JSON could not be redacted"),
|
||||||
|
}
|
||||||
|
}
|
||||||
verifyRequests := []gomatrixserverlib.VerifyJSONRequest{{
|
verifyRequests := []gomatrixserverlib.VerifyJSONRequest{{
|
||||||
ServerName: event.Origin(),
|
ServerName: event.Origin(),
|
||||||
Message: redacted.JSON(),
|
Message: redacted,
|
||||||
AtTS: event.OriginServerTS(),
|
AtTS: event.OriginServerTS(),
|
||||||
StrictValidityChecking: true,
|
StrictValidityChecking: true,
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -266,10 +266,17 @@ func SendJoin(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the event is signed by the server sending the request.
|
// Check that the event is signed by the server sending the request.
|
||||||
redacted := event.Redact()
|
redacted, err := gomatrixserverlib.RedactEventJSON(event.JSON(), event.Version())
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Errorf("XXX: join.go")
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: jsonerror.BadJSON("The event JSON could not be redacted"),
|
||||||
|
}
|
||||||
|
}
|
||||||
verifyRequests := []gomatrixserverlib.VerifyJSONRequest{{
|
verifyRequests := []gomatrixserverlib.VerifyJSONRequest{{
|
||||||
ServerName: event.Origin(),
|
ServerName: event.Origin(),
|
||||||
Message: redacted.JSON(),
|
Message: redacted,
|
||||||
AtTS: event.OriginServerTS(),
|
AtTS: event.OriginServerTS(),
|
||||||
StrictValidityChecking: true,
|
StrictValidityChecking: true,
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -231,10 +231,17 @@ func SendLeave(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the event is signed by the server sending the request.
|
// Check that the event is signed by the server sending the request.
|
||||||
redacted := event.Redact()
|
redacted, err := gomatrixserverlib.RedactEventJSON(event.JSON(), event.Version())
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Errorf("XXX: leave.go")
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: jsonerror.BadJSON("The event JSON could not be redacted"),
|
||||||
|
}
|
||||||
|
}
|
||||||
verifyRequests := []gomatrixserverlib.VerifyJSONRequest{{
|
verifyRequests := []gomatrixserverlib.VerifyJSONRequest{{
|
||||||
ServerName: event.Origin(),
|
ServerName: event.Origin(),
|
||||||
Message: redacted.JSON(),
|
Message: redacted,
|
||||||
AtTS: event.OriginServerTS(),
|
AtTS: event.OriginServerTS(),
|
||||||
StrictValidityChecking: true,
|
StrictValidityChecking: true,
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -15,23 +15,13 @@
|
||||||
package deltas
|
package deltas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
|
||||||
"github.com/pressly/goose"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadFromGoose() {
|
func UpRemoveRoomsTable(ctx context.Context, tx *sql.Tx) error {
|
||||||
goose.AddMigration(UpRemoveRoomsTable, DownRemoveRoomsTable)
|
_, err := tx.ExecContext(ctx, `
|
||||||
}
|
|
||||||
|
|
||||||
func LoadRemoveRoomsTable(m *sqlutil.Migrations) {
|
|
||||||
m.AddMigration(UpRemoveRoomsTable, DownRemoveRoomsTable)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpRemoveRoomsTable(tx *sql.Tx) error {
|
|
||||||
_, err := tx.Exec(`
|
|
||||||
DROP TABLE IF EXISTS federationsender_rooms;
|
DROP TABLE IF EXISTS federationsender_rooms;
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -82,9 +82,13 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
m := sqlutil.NewMigrations()
|
m := sqlutil.NewMigrator(d.db)
|
||||||
deltas.LoadRemoveRoomsTable(m)
|
m.AddMigrations(sqlutil.Migration{
|
||||||
if err = m.RunDeltas(d.db, dbProperties); err != nil {
|
Version: "federationsender: drop federationsender_rooms",
|
||||||
|
Up: deltas.UpRemoveRoomsTable,
|
||||||
|
})
|
||||||
|
err = m.Up(base.Context())
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
d.Database = shared.Database{
|
d.Database = shared.Database{
|
||||||
|
|
|
||||||
|
|
@ -15,23 +15,13 @@
|
||||||
package deltas
|
package deltas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
|
||||||
"github.com/pressly/goose"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadFromGoose() {
|
func UpRemoveRoomsTable(ctx context.Context, tx *sql.Tx) error {
|
||||||
goose.AddMigration(UpRemoveRoomsTable, DownRemoveRoomsTable)
|
_, err := tx.ExecContext(ctx, `
|
||||||
}
|
|
||||||
|
|
||||||
func LoadRemoveRoomsTable(m *sqlutil.Migrations) {
|
|
||||||
m.AddMigration(UpRemoveRoomsTable, DownRemoveRoomsTable)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpRemoveRoomsTable(tx *sql.Tx) error {
|
|
||||||
_, err := tx.Exec(`
|
|
||||||
DROP TABLE IF EXISTS federationsender_rooms;
|
DROP TABLE IF EXISTS federationsender_rooms;
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -81,9 +81,13 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
m := sqlutil.NewMigrations()
|
m := sqlutil.NewMigrator(d.db)
|
||||||
deltas.LoadRemoveRoomsTable(m)
|
m.AddMigrations(sqlutil.Migration{
|
||||||
if err = m.RunDeltas(d.db, dbProperties); err != nil {
|
Version: "federationsender: drop federationsender_rooms",
|
||||||
|
Up: deltas.UpRemoveRoomsTable,
|
||||||
|
})
|
||||||
|
err = m.Up(base.Context())
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
d.Database = shared.Database{
|
d.Database = shared.Database{
|
||||||
|
|
|
||||||
94
go.mod
94
go.mod
|
|
@ -1,24 +1,15 @@
|
||||||
module github.com/matrix-org/dendrite
|
module github.com/matrix-org/dendrite
|
||||||
|
|
||||||
replace github.com/nats-io/nats-server/v2 => github.com/neilalexander/nats-server/v2 v2.8.3-0.20220513095553-73a9a246d34f
|
|
||||||
|
|
||||||
replace github.com/nats-io/nats.go => github.com/neilalexander/nats.go v1.13.1-0.20220621084451-ac518c356673
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Arceliar/ironwood v0.0.0-20220306165321-319147a02d98
|
github.com/Arceliar/ironwood v0.0.0-20220306165321-319147a02d98
|
||||||
github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979
|
github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.0
|
github.com/DATA-DOG/go-sqlmock v1.5.0
|
||||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
|
|
||||||
github.com/MFAshby/stdemuxerhook v1.0.0
|
github.com/MFAshby/stdemuxerhook v1.0.0
|
||||||
github.com/Masterminds/semver/v3 v3.1.1
|
github.com/Masterminds/semver/v3 v3.1.1
|
||||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
|
||||||
github.com/codeclysm/extract v2.2.0+incompatible
|
github.com/codeclysm/extract v2.2.0+incompatible
|
||||||
github.com/docker/distribution v2.7.1+incompatible // indirect
|
github.com/dgraph-io/ristretto v0.1.1-0.20220403145359-8e850b710d6d
|
||||||
github.com/docker/docker v20.10.16+incompatible
|
github.com/docker/docker v20.10.16+incompatible
|
||||||
github.com/docker/go-connections v0.4.0
|
github.com/docker/go-connections v0.4.0
|
||||||
github.com/docker/go-units v0.4.0 // indirect
|
|
||||||
github.com/frankban/quicktest v1.14.3 // indirect
|
|
||||||
github.com/getsentry/sentry-go v0.13.0
|
github.com/getsentry/sentry-go v0.13.0
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.4.1
|
github.com/golang-jwt/jwt/v4 v4.4.1
|
||||||
|
|
@ -27,38 +18,26 @@ require (
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/gorilla/websocket v1.5.0
|
github.com/gorilla/websocket v1.5.0
|
||||||
github.com/h2non/filetype v1.1.3 // indirect
|
|
||||||
github.com/hashicorp/golang-lru v0.5.4
|
|
||||||
github.com/juju/testing v0.0.0-20220203020004-a0ff61f03494 // indirect
|
|
||||||
github.com/kardianos/minwinsvc v1.0.0
|
github.com/kardianos/minwinsvc v1.0.0
|
||||||
github.com/lib/pq v1.10.5
|
github.com/lib/pq v1.10.5
|
||||||
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e
|
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e
|
||||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
|
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
|
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20220701090733-da53994b0c7f
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20220725104114-b6003e522771
|
||||||
github.com/matrix-org/pinecone v0.0.0-20220408153826-2999ea29ed48
|
github.com/matrix-org/pinecone v0.0.0-20220708135211-1ce778fcde6a
|
||||||
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4
|
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4
|
||||||
github.com/matryer/is v1.4.0
|
github.com/matryer/is v1.4.0
|
||||||
github.com/mattn/go-sqlite3 v1.14.13
|
github.com/mattn/go-sqlite3 v1.14.13
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
github.com/nats-io/nats-server/v2 v2.8.5-0.20220731184415-903a06a5b4ee
|
||||||
github.com/miekg/dns v1.1.49 // indirect
|
github.com/nats-io/nats.go v1.16.1-0.20220731182438-87bbea85922b
|
||||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect
|
|
||||||
github.com/morikuni/aec v1.0.0 // indirect
|
|
||||||
github.com/nats-io/nats-server/v2 v2.7.4-0.20220309205833-773636c1c5bb
|
|
||||||
github.com/nats-io/nats.go v1.14.0
|
|
||||||
github.com/neilalexander/utp v0.1.1-0.20210727203401-54ae7b1cd5f9
|
github.com/neilalexander/utp v0.1.1-0.20210727203401-54ae7b1cd5f9
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||||
github.com/ngrok/sqlmw v0.0.0-20220520173518-97c9c04efc79
|
github.com/ngrok/sqlmw v0.0.0-20220520173518-97c9c04efc79
|
||||||
github.com/onsi/gomega v1.17.0 // indirect
|
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
|
||||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
|
||||||
github.com/opentracing/opentracing-go v1.2.0
|
github.com/opentracing/opentracing-go v1.2.0
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/pressly/goose v2.7.0+incompatible
|
|
||||||
github.com/prometheus/client_golang v1.12.2
|
github.com/prometheus/client_golang v1.12.2
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/stretchr/objx v0.2.0 // indirect
|
|
||||||
github.com/stretchr/testify v1.7.1
|
github.com/stretchr/testify v1.7.1
|
||||||
github.com/tidwall/gjson v1.14.1
|
github.com/tidwall/gjson v1.14.1
|
||||||
github.com/tidwall/sjson v1.2.4
|
github.com/tidwall/sjson v1.2.4
|
||||||
|
|
@ -70,14 +49,67 @@ require (
|
||||||
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9
|
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9
|
||||||
golang.org/x/mobile v0.0.0-20220518205345-8578da9835fd
|
golang.org/x/mobile v0.0.0-20220518205345-8578da9835fd
|
||||||
golang.org/x/net v0.0.0-20220524220425-1d687d428aca
|
golang.org/x/net v0.0.0-20220524220425-1d687d428aca
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
|
||||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467
|
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467
|
||||||
google.golang.org/protobuf v1.27.1 // indirect
|
|
||||||
gopkg.in/h2non/bimg.v1 v1.1.9
|
gopkg.in/h2non/bimg.v1 v1.1.9
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
gopkg.in/yaml.v3 v3.0.0 // indirect
|
|
||||||
gotest.tools/v3 v3.0.3 // indirect
|
|
||||||
nhooyr.io/websocket v1.8.7
|
nhooyr.io/websocket v1.8.7
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.16
|
require (
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||||
|
github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
|
||||||
|
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||||
|
github.com/cheekybits/genny v1.0.0 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||||
|
github.com/docker/go-units v0.4.0 // indirect
|
||||||
|
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||||
|
github.com/frankban/quicktest v1.14.3 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||||
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/h2non/filetype v1.1.3 // indirect
|
||||||
|
github.com/juju/errors v0.0.0-20220203013757-bd733f3c86b9 // indirect
|
||||||
|
github.com/juju/testing v0.0.0-20220203020004-a0ff61f03494 // indirect
|
||||||
|
github.com/klauspost/compress v1.15.9 // indirect
|
||||||
|
github.com/lucas-clemente/quic-go v0.26.0 // indirect
|
||||||
|
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
||||||
|
github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect
|
||||||
|
github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||||
|
github.com/miekg/dns v1.1.49 // indirect
|
||||||
|
github.com/minio/highwayhash v1.0.2 // indirect
|
||||||
|
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect
|
||||||
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
|
github.com/nats-io/jwt/v2 v2.3.0 // indirect
|
||||||
|
github.com/nats-io/nkeys v0.3.0 // indirect
|
||||||
|
github.com/nats-io/nuid v1.0.1 // indirect
|
||||||
|
github.com/nxadm/tail v1.4.8 // indirect
|
||||||
|
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||||
|
github.com/onsi/gomega v1.17.0 // indirect
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // 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/stretchr/objx v0.2.0 // indirect
|
||||||
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
|
github.com/tidwall/pretty v1.2.0 // indirect
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||||
|
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b // indirect
|
||||||
|
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
|
||||||
|
golang.org/x/tools v0.1.10 // indirect
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
|
gopkg.in/macaroon.v2 v2.1.0 // indirect
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.0 // indirect
|
||||||
|
gotest.tools/v3 v3.0.3 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
|
||||||
201
go.sum
201
go.sum
|
|
@ -38,7 +38,6 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr
|
||||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
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=
|
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||||
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
|
||||||
github.com/Arceliar/ironwood v0.0.0-20211125050254-8951369625d0/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk=
|
github.com/Arceliar/ironwood v0.0.0-20211125050254-8951369625d0/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk=
|
||||||
github.com/Arceliar/ironwood v0.0.0-20220306165321-319147a02d98 h1:PsaZb47k7WB1V+AlGpb+W7SM+ZOhp16vVevg5gl9YkU=
|
github.com/Arceliar/ironwood v0.0.0-20220306165321-319147a02d98 h1:PsaZb47k7WB1V+AlGpb+W7SM+ZOhp16vVevg5gl9YkU=
|
||||||
github.com/Arceliar/ironwood v0.0.0-20220306165321-319147a02d98/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk=
|
github.com/Arceliar/ironwood v0.0.0-20220306165321-319147a02d98/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk=
|
||||||
|
|
@ -49,13 +48,10 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
|
|
||||||
github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
|
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
|
github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
|
||||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||||
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
|
||||||
github.com/MFAshby/stdemuxerhook v1.0.0 h1:1XFGzakrsHMv76AeanPDL26NOgwjPl/OUxbGhJthwMc=
|
github.com/MFAshby/stdemuxerhook v1.0.0 h1:1XFGzakrsHMv76AeanPDL26NOgwjPl/OUxbGhJthwMc=
|
||||||
github.com/MFAshby/stdemuxerhook v1.0.0/go.mod h1:nLMI9FUf9Hz98n+yAXsTMUR4RZQy28uCTLG1Fzvj/uY=
|
github.com/MFAshby/stdemuxerhook v1.0.0/go.mod h1:nLMI9FUf9Hz98n+yAXsTMUR4RZQy28uCTLG1Fzvj/uY=
|
||||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||||
|
|
@ -65,10 +61,8 @@ github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpz
|
||||||
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
||||||
github.com/RyanCarrier/dijkstra v1.0.0/go.mod h1:5agGUBNEtUAGIANmbw09fuO3a2htPEkc1jNH01qxCWA=
|
github.com/RyanCarrier/dijkstra v1.0.0/go.mod h1:5agGUBNEtUAGIANmbw09fuO3a2htPEkc1jNH01qxCWA=
|
||||||
github.com/RyanCarrier/dijkstra-1 v0.0.0-20170512020943-0e5801a26345/go.mod h1:OK4EvWJ441LQqGzed5NGB6vKBAE34n3z7iayPcEwr30=
|
github.com/RyanCarrier/dijkstra-1 v0.0.0-20170512020943-0e5801a26345/go.mod h1:OK4EvWJ441LQqGzed5NGB6vKBAE34n3z7iayPcEwr30=
|
||||||
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
|
|
||||||
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
||||||
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
|
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
|
||||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
|
||||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||||
github.com/albertorestifo/dijkstra v0.0.0-20160910063646-aba76f725f72/go.mod h1:o+JdB7VetTHjLhU0N57x18B9voDBQe0paApdEAEoEfw=
|
github.com/albertorestifo/dijkstra v0.0.0-20160910063646-aba76f725f72/go.mod h1:o+JdB7VetTHjLhU0N57x18B9voDBQe0paApdEAEoEfw=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
|
@ -88,8 +82,6 @@ github.com/anacrolix/missinggo v1.2.1/go.mod h1:J5cMhif8jPmFoC3+Uvob3OXXNIhOUikz
|
||||||
github.com/anacrolix/missinggo/perf v1.0.0/go.mod h1:ljAFWkBuzkO12MQclXzZrosP5urunoLS0Cbvb4V0uMQ=
|
github.com/anacrolix/missinggo/perf v1.0.0/go.mod h1:ljAFWkBuzkO12MQclXzZrosP5urunoLS0Cbvb4V0uMQ=
|
||||||
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
|
||||||
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
|
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
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.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
|
@ -114,18 +106,15 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/codeclysm/extract v2.2.0+incompatible h1:q3wyckoA30bhUSiwdQezMqVhwd8+WGE64/GL//LtUhI=
|
github.com/codeclysm/extract v2.2.0+incompatible h1:q3wyckoA30bhUSiwdQezMqVhwd8+WGE64/GL//LtUhI=
|
||||||
github.com/codeclysm/extract v2.2.0+incompatible/go.mod h1:2nhFMPHiU9At61hz+12bfrlpXSUrOnK+wR+KlGO4Uks=
|
github.com/codeclysm/extract v2.2.0+incompatible/go.mod h1:2nhFMPHiU9At61hz+12bfrlpXSUrOnK+wR+KlGO4Uks=
|
||||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
|
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
|
||||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
|
github.com/dgraph-io/ristretto v0.1.1-0.20220403145359-8e850b710d6d h1:Wrc3UKTS+cffkOx0xRGFC+ZesNuTfn0ThvEC72N0krk=
|
||||||
|
github.com/dgraph-io/ristretto v0.1.1-0.20220403145359-8e850b710d6d/go.mod h1:RAy2GVV4sTWVlNMavv3xhLsk18rxhfhDnombTe6EF5c=
|
||||||
|
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
|
|
@ -137,16 +126,14 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
|
||||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
|
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
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.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/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/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
|
|
||||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
|
||||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||||
|
|
@ -157,7 +144,6 @@ github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUork
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
|
|
||||||
github.com/getsentry/sentry-go v0.13.0 h1:20dgTiUSfxRB/EhMPtxcL9ZEbM1ZdR+W/7f7NWD+xWo=
|
github.com/getsentry/sentry-go v0.13.0 h1:20dgTiUSfxRB/EhMPtxcL9ZEbM1ZdR+W/7f7NWD+xWo=
|
||||||
github.com/getsentry/sentry-go v0.13.0/go.mod h1:EOsfu5ZdvKPfeHYV6pTVQnsjfp30+XA7//UooKNumH0=
|
github.com/getsentry/sentry-go v0.13.0/go.mod h1:EOsfu5ZdvKPfeHYV6pTVQnsjfp30+XA7//UooKNumH0=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
|
@ -165,11 +151,9 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||||
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
||||||
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
|
||||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||||
github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
|
||||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
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 v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
|
|
@ -181,7 +165,6 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
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.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
|
|
@ -189,7 +172,6 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87
|
||||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
|
|
@ -202,11 +184,10 @@ github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/E
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
|
||||||
github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ=
|
github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ=
|
||||||
github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
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-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-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
|
@ -242,7 +223,6 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l
|
||||||
github.com/gologme/log v1.2.0/go.mod h1:gq31gQ8wEHkR+WekdWsqDuf8pXTUZA9BnnzTuPz1Y9U=
|
github.com/gologme/log v1.2.0/go.mod h1:gq31gQ8wEHkR+WekdWsqDuf8pXTUZA9BnnzTuPz1Y9U=
|
||||||
github.com/gologme/log v1.3.0 h1:l781G4dE+pbigClDSDzSaaYKtiueHCILUa/qSDsmHAo=
|
github.com/gologme/log v1.3.0 h1:l781G4dE+pbigClDSDzSaaYKtiueHCILUa/qSDsmHAo=
|
||||||
github.com/gologme/log v1.3.0/go.mod h1:yKT+DvIPdDdDoPtqFrFxheooyVmoqi0BAsw+erN3wA4=
|
github.com/gologme/log v1.3.0/go.mod h1:yKT+DvIPdDdDoPtqFrFxheooyVmoqi0BAsw+erN3wA4=
|
||||||
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
|
||||||
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
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/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
|
@ -292,24 +272,13 @@ github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||||
github.com/hashicorp/go-version v1.2.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.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/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
|
||||||
github.com/hjson/hjson-go v3.1.0+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio=
|
github.com/hjson/hjson-go v3.1.0+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/huandu/xstrings v1.0.0 h1:pO2K/gKgKaat5LdpAhxhluX2GPQMaI3W5FUz/I/UnWk=
|
github.com/huandu/xstrings v1.0.0 h1:pO2K/gKgKaat5LdpAhxhluX2GPQMaI3W5FUz/I/UnWk=
|
||||||
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
|
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
|
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
|
||||||
github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
|
|
||||||
github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
|
|
||||||
github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
|
|
||||||
github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
|
|
||||||
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
|
|
||||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
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.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
|
@ -321,67 +290,28 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
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/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
|
||||||
github.com/juju/ansiterm v0.0.0-20160907234532-b99631de12cf/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
|
|
||||||
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
|
|
||||||
github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA=
|
|
||||||
github.com/juju/cmd v0.0.0-20171107070456-e74f39857ca0/go.mod h1:yWJQHl73rdSX4DHVKGqkAip+huBslxRwS8m9CrOLq18=
|
|
||||||
github.com/juju/collections v0.0.0-20200605021417-0d0ec82b7271/go.mod h1:5XgO71dV1JClcOJE+4dzdn4HrI5LiyKd7PlVG6eZYhY=
|
|
||||||
github.com/juju/errors v0.0.0-20150916125642-1b5e39b83d18/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
|
|
||||||
github.com/juju/errors v0.0.0-20200330140219-3fe23663418f/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
|
|
||||||
github.com/juju/errors v0.0.0-20220203013757-bd733f3c86b9 h1:EJHbsNpQyupmMeWTq7inn+5L/WZ7JfzCVPJ+DP9McCQ=
|
github.com/juju/errors v0.0.0-20220203013757-bd733f3c86b9 h1:EJHbsNpQyupmMeWTq7inn+5L/WZ7JfzCVPJ+DP9McCQ=
|
||||||
github.com/juju/errors v0.0.0-20220203013757-bd733f3c86b9/go.mod h1:TRm7EVGA3mQOqSVcBySRY7a9Y1/gyVhh/WTCnc5sD4U=
|
github.com/juju/errors v0.0.0-20220203013757-bd733f3c86b9/go.mod h1:TRm7EVGA3mQOqSVcBySRY7a9Y1/gyVhh/WTCnc5sD4U=
|
||||||
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
|
|
||||||
github.com/juju/httpprof v0.0.0-20141217160036-14bf14c30767/go.mod h1:+MaLYz4PumRkkyHYeXJ2G5g5cIW0sli2bOfpmbaMV/g=
|
|
||||||
github.com/juju/loggo v0.0.0-20170605014607-8232ab8918d9/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
|
|
||||||
github.com/juju/loggo v0.0.0-20200526014432-9ce3a2e09b5e/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
|
|
||||||
github.com/juju/loggo v0.0.0-20210728185423-eebad3a902c4 h1:NO5tuyw++EGLnz56Q8KMyDZRwJwWO8jQnj285J3FOmY=
|
github.com/juju/loggo v0.0.0-20210728185423-eebad3a902c4 h1:NO5tuyw++EGLnz56Q8KMyDZRwJwWO8jQnj285J3FOmY=
|
||||||
github.com/juju/loggo v0.0.0-20210728185423-eebad3a902c4/go.mod h1:NIXFioti1SmKAlKNuUwbMenNdef59IF52+ZzuOmHYkg=
|
|
||||||
github.com/juju/mgo/v2 v2.0.0-20210302023703-70d5d206e208 h1:/WiCm+Vpj87e4QWuWwPD/bNE9kDrWCLvPBHOQNcG2+A=
|
github.com/juju/mgo/v2 v2.0.0-20210302023703-70d5d206e208 h1:/WiCm+Vpj87e4QWuWwPD/bNE9kDrWCLvPBHOQNcG2+A=
|
||||||
github.com/juju/mgo/v2 v2.0.0-20210302023703-70d5d206e208/go.mod h1:0OChplkvPTZ174D2FYZXg4IB9hbEwyHkD+zT+/eK+Fg=
|
|
||||||
github.com/juju/mutex v0.0.0-20171110020013-1fe2a4bf0a3a/go.mod h1:Y3oOzHH8CQ0Ppt0oCKJ2JFO81/EsWenH5AEqigLH+yY=
|
|
||||||
github.com/juju/retry v0.0.0-20151029024821-62c620325291/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4=
|
|
||||||
github.com/juju/retry v0.0.0-20180821225755-9058e192b216/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4=
|
|
||||||
github.com/juju/testing v0.0.0-20180402130637-44801989f0f7/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
|
|
||||||
github.com/juju/testing v0.0.0-20190723135506-ce30eb24acd2/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
|
|
||||||
github.com/juju/testing v0.0.0-20210302031854-2c7ee8570c07/go.mod h1:7lxZW0B50+xdGFkvhAb8bwAGt6IU87JB1H9w4t8MNVM=
|
|
||||||
github.com/juju/testing v0.0.0-20220202055744-1ad0816210a6/go.mod h1:QgWc2UdIPJ8t3rnvv95tFNOsQDfpXYEZDbP281o3b2c=
|
|
||||||
github.com/juju/testing v0.0.0-20220203020004-a0ff61f03494 h1:XEDzpuZb8Ma7vLja3+5hzUqVTvAqm5Y+ygvnDs5iTMM=
|
github.com/juju/testing v0.0.0-20220203020004-a0ff61f03494 h1:XEDzpuZb8Ma7vLja3+5hzUqVTvAqm5Y+ygvnDs5iTMM=
|
||||||
github.com/juju/testing v0.0.0-20220203020004-a0ff61f03494/go.mod h1:rUquetT0ALL48LHZhyRGvjjBH8xZaZ8dFClulKK5wK4=
|
github.com/juju/testing v0.0.0-20220203020004-a0ff61f03494/go.mod h1:rUquetT0ALL48LHZhyRGvjjBH8xZaZ8dFClulKK5wK4=
|
||||||
github.com/juju/utils v0.0.0-20180424094159-2000ea4ff043/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk=
|
|
||||||
github.com/juju/utils v0.0.0-20200116185830-d40c2fe10647/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk=
|
|
||||||
github.com/juju/utils/v2 v2.0.0-20200923005554-4646bfea2ef1/go.mod h1:fdlDtQlzundleLLz/ggoYinEt/LmnrpNKcNTABQATNI=
|
|
||||||
github.com/juju/utils/v3 v3.0.0-20220130232349-cd7ecef0e94a/go.mod h1:LzwbbEN7buYjySp4nqnti6c6olSqRXUk6RkbSUUP1n8=
|
|
||||||
github.com/juju/version v0.0.0-20161031051906-1f41e27e54f2/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U=
|
|
||||||
github.com/juju/version v0.0.0-20180108022336-b64dbd566305/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U=
|
|
||||||
github.com/juju/version v0.0.0-20191219164919-81c1be00b9a6/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U=
|
|
||||||
github.com/juju/version/v2 v2.0.0-20211007103408-2e8da085dc23/go.mod h1:Ljlbryh9sYaUSGXucslAEDf0A2XUSGvDbHJgW8ps6nc=
|
|
||||||
github.com/julienschmidt/httprouter v1.1.1-0.20151013225520-77a895ad01eb/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
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/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||||
github.com/kardianos/minwinsvc v1.0.0 h1:+JfAi8IBJna0jY2dJGZqi7o15z13JelFIklJCAENALA=
|
github.com/kardianos/minwinsvc v1.0.0 h1:+JfAi8IBJna0jY2dJGZqi7o15z13JelFIklJCAENALA=
|
||||||
github.com/kardianos/minwinsvc v1.0.0/go.mod h1:Bgd0oc+D0Qo3bBytmNtyRKVlp85dAloLKhfxanPFFRc=
|
github.com/kardianos/minwinsvc v1.0.0/go.mod h1:Bgd0oc+D0Qo3bBytmNtyRKVlp85dAloLKhfxanPFFRc=
|
||||||
github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8=
|
|
||||||
github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE=
|
|
||||||
github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
|
|
||||||
github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro=
|
|
||||||
github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
|
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
|
||||||
github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
|
||||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
github.com/klauspost/compress v1.14.4 h1:eijASRJcobkVtSt81Olfh7JX43osYLwy5krOJo6YEu4=
|
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
|
||||||
github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
|
||||||
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.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/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/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/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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
|
@ -389,19 +319,15 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
|
|
||||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
|
||||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
|
github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
|
||||||
github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/lucas-clemente/quic-go v0.26.0 h1:ALBQXr9UJ8A1LyzvceX4jd9QFsHvlI0RR6BkV16o00A=
|
github.com/lucas-clemente/quic-go v0.26.0 h1:ALBQXr9UJ8A1LyzvceX4jd9QFsHvlI0RR6BkV16o00A=
|
||||||
github.com/lucas-clemente/quic-go v0.26.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
|
github.com/lucas-clemente/quic-go v0.26.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
|
||||||
github.com/lunixbochs/vtclean v0.0.0-20160125035106-4fbf7632a2c6/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
|
||||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||||
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
|
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
|
||||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
|
github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
|
||||||
|
|
@ -410,10 +336,6 @@ github.com/marten-seemann/qtls-go1-17 v0.1.1 h1:DQjHPq+aOzUeh9/lixAGunn6rIOQyWCh
|
||||||
github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
|
github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
|
||||||
github.com/marten-seemann/qtls-go1-18 v0.1.1 h1:qp7p7XXUFL7fpBvSS1sWD+uSqPvzNQK43DH+/qEkj0Y=
|
github.com/marten-seemann/qtls-go1-18 v0.1.1 h1:qp7p7XXUFL7fpBvSS1sWD+uSqPvzNQK43DH+/qEkj0Y=
|
||||||
github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||||
github.com/masterzen/azure-sdk-for-go v3.2.0-beta.0.20161014135628-ee4f0065d00c+incompatible/go.mod h1:mf8fjOu33zCqxUjuiU3I8S1lJMyEAlH+0F2+M5xl3hE=
|
|
||||||
github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc=
|
|
||||||
github.com/masterzen/winrm v0.0.0-20161014151040-7a535cd943fc/go.mod h1:CfZSN7zwz5gJiFhZJz49Uzk7mEBHIceWmbFmYx7Hf7E=
|
|
||||||
github.com/masterzen/xmlpath v0.0.0-20140218185901-13f4951698ad/go.mod h1:A0zPC53iKKKcXYxr4ROjpQRQ5FgJXtelNdSmHHuq/tY=
|
|
||||||
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e h1:DP5RC0Z3XdyBEW5dKt8YPeN6vZbm6OzVaGVp7f1BQRM=
|
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e h1:DP5RC0Z3XdyBEW5dKt8YPeN6vZbm6OzVaGVp7f1BQRM=
|
||||||
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e/go.mod h1:NgPCr+UavRGH6n5jmdX8DuqFZ4JiCWIJoZiuhTRLSUg=
|
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e/go.mod h1:NgPCr+UavRGH6n5jmdX8DuqFZ4JiCWIJoZiuhTRLSUg=
|
||||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91 h1:s7fexw2QV3YD/fRrzEDPNGgTlJlvXY0EHHnT87wF3OA=
|
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91 h1:s7fexw2QV3YD/fRrzEDPNGgTlJlvXY0EHHnT87wF3OA=
|
||||||
|
|
@ -421,45 +343,33 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91/go.mod h1
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0=
|
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0=
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4=
|
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4=
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20220701090733-da53994b0c7f h1:XF2+J6sOq07yhK1I7ItwsgRwXorjj7gqiCvgZ4dn8W8=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20220725104114-b6003e522771 h1:ZIPHFIPNDS9dmEbPEiJbNmyCGJtn9exfpLC7JOcn/bE=
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20220701090733-da53994b0c7f/go.mod h1:jX38yp3SSLJNftBg3PXU1ayd0PCLIiDHQ4xAc9DIixk=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20220725104114-b6003e522771/go.mod h1:jX38yp3SSLJNftBg3PXU1ayd0PCLIiDHQ4xAc9DIixk=
|
||||||
github.com/matrix-org/pinecone v0.0.0-20220408153826-2999ea29ed48 h1:W0sjjC6yjskHX4mb0nk3p0fXAlbU5bAFUFeEtlrPASE=
|
github.com/matrix-org/pinecone v0.0.0-20220708135211-1ce778fcde6a h1:DdG8vXMlZ65EAtc4V+3t7zHZ2Gqs24pSnyXS+4BRHUs=
|
||||||
github.com/matrix-org/pinecone v0.0.0-20220408153826-2999ea29ed48/go.mod h1:ulJzsVOTssIVp1j/m5eI//4VpAGDkMt5NrRuAVX7wpc=
|
github.com/matrix-org/pinecone v0.0.0-20220708135211-1ce778fcde6a/go.mod h1:ulJzsVOTssIVp1j/m5eI//4VpAGDkMt5NrRuAVX7wpc=
|
||||||
github.com/matrix-org/util v0.0.0-20190711121626-527ce5ddefc7/go.mod h1:vVQlW/emklohkZnOPwD3LrZUBqdfsbiyO3p1lNV8F6U=
|
github.com/matrix-org/util v0.0.0-20190711121626-527ce5ddefc7/go.mod h1:vVQlW/emklohkZnOPwD3LrZUBqdfsbiyO3p1lNV8F6U=
|
||||||
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4 h1:eCEHXWDv9Rm335MSuB49mFUK44bwZPFSDde3ORE3syk=
|
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4 h1:eCEHXWDv9Rm335MSuB49mFUK44bwZPFSDde3ORE3syk=
|
||||||
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4/go.mod h1:vVQlW/emklohkZnOPwD3LrZUBqdfsbiyO3p1lNV8F6U=
|
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4/go.mod h1:vVQlW/emklohkZnOPwD3LrZUBqdfsbiyO3p1lNV8F6U=
|
||||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||||
github.com/mattn/go-colorable v0.0.6/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
|
||||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
|
||||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
|
||||||
github.com/mattn/go-isatty v0.0.0-20160806122752-66b8e73f3f5c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
|
||||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mattn/go-sqlite3 v1.14.13 h1:1tj15ngiFfcZzii7yd82foL+ks+ouQcj8j/TPq3fk1I=
|
github.com/mattn/go-sqlite3 v1.14.13 h1:1tj15ngiFfcZzii7yd82foL+ks+ouQcj8j/TPq3fk1I=
|
||||||
github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
|
||||||
github.com/mattomatic/dijkstra v0.0.0-20130617153013-6f6d134eb237/go.mod h1:UOnLAUmVG5paym8pD3C4B9BQylUDC2vXFJJpT7JrlEA=
|
github.com/mattomatic/dijkstra v0.0.0-20130617153013-6f6d134eb237/go.mod h1:UOnLAUmVG5paym8pD3C4B9BQylUDC2vXFJJpT7JrlEA=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
|
|
||||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
|
|
||||||
github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||||
github.com/miekg/dns v1.1.49 h1:qe0mQU3Z/XpFeE+AEBo2rqaS1IPBJ3anmqZ4XiZJVG8=
|
github.com/miekg/dns v1.1.49 h1:qe0mQU3Z/XpFeE+AEBo2rqaS1IPBJ3anmqZ4XiZJVG8=
|
||||||
github.com/miekg/dns v1.1.49/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
github.com/miekg/dns v1.1.49/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||||
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
|
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
|
||||||
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0=
|
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0=
|
||||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
|
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
|
||||||
|
|
@ -472,12 +382,15 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
|
||||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
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/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/nats-io/jwt/v2 v2.2.1-0.20220330180145-442af02fd36a h1:lem6QCvxR0Y28gth9P+wV2K/zYUUAkJ+55U8cpS0p5I=
|
github.com/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI=
|
||||||
github.com/nats-io/jwt/v2 v2.2.1-0.20220330180145-442af02fd36a/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k=
|
github.com/nats-io/jwt/v2 v2.3.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k=
|
||||||
|
github.com/nats-io/nats-server/v2 v2.8.5-0.20220731184415-903a06a5b4ee h1:vAtoZ+LW6eIUjkCWWwO1DZ6o16UGrVOG+ot/AkwejO8=
|
||||||
|
github.com/nats-io/nats-server/v2 v2.8.5-0.20220731184415-903a06a5b4ee/go.mod h1:3Yg3ApyQxPlAs1KKHKV5pobV5VtZk+TtOiUJx/iqkkg=
|
||||||
|
github.com/nats-io/nats.go v1.16.1-0.20220731182438-87bbea85922b h1:CE9wSYLvwq8aC/0+6zH8lhhtZYvJ9p8PzwvZeYgdBc0=
|
||||||
|
github.com/nats-io/nats.go v1.16.1-0.20220731182438-87bbea85922b/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
|
||||||
github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
|
github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
|
||||||
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
|
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
|
||||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||||
|
|
@ -485,10 +398,6 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS
|
||||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
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/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||||
github.com/neilalexander/nats-server/v2 v2.8.3-0.20220513095553-73a9a246d34f h1:Fc+TjdV1mOy0oISSzfoxNWdTqjg7tN/Vdgf+B2cwvdo=
|
|
||||||
github.com/neilalexander/nats-server/v2 v2.8.3-0.20220513095553-73a9a246d34f/go.mod h1:vIdpKz3OG+DCg4q/xVPdXHoztEyKDWRtykQ4N7hd7C4=
|
|
||||||
github.com/neilalexander/nats.go v1.13.1-0.20220621084451-ac518c356673 h1:TcKfa3Tf0qwUotv63PQVu2d1bBoLi2iEA4RHVMGDh5M=
|
|
||||||
github.com/neilalexander/nats.go v1.13.1-0.20220621084451-ac518c356673/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
|
|
||||||
github.com/neilalexander/utp v0.1.1-0.20210727203401-54ae7b1cd5f9 h1:lrVQzBtkeQEGGYUHwSX1XPe1E5GL6U3KYCNe2G4bncQ=
|
github.com/neilalexander/utp v0.1.1-0.20210727203401-54ae7b1cd5f9 h1:lrVQzBtkeQEGGYUHwSX1XPe1E5GL6U3KYCNe2G4bncQ=
|
||||||
github.com/neilalexander/utp v0.1.1-0.20210727203401-54ae7b1cd5f9/go.mod h1:NPHGhPc0/wudcaCqL/H5AOddkRf8GPRhzOujuUKGQu8=
|
github.com/neilalexander/utp v0.1.1-0.20210727203401-54ae7b1cd5f9/go.mod h1:NPHGhPc0/wudcaCqL/H5AOddkRf8GPRhzOujuUKGQu8=
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||||
|
|
@ -496,7 +405,6 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S
|
||||||
github.com/ngrok/sqlmw v0.0.0-20220520173518-97c9c04efc79 h1:Dmx8g2747UTVPzSkmohk84S3g/uWqd6+f4SSLPhLcfA=
|
github.com/ngrok/sqlmw v0.0.0-20220520173518-97c9c04efc79 h1:Dmx8g2747UTVPzSkmohk84S3g/uWqd6+f4SSLPhLcfA=
|
||||||
github.com/ngrok/sqlmw v0.0.0-20220520173518-97c9c04efc79/go.mod h1:E26fwEtRNigBfFfHDWsklmo0T7Ixbg0XXgck+Hq4O9k=
|
github.com/ngrok/sqlmw v0.0.0-20220520173518-97c9c04efc79/go.mod h1:E26fwEtRNigBfFfHDWsklmo0T7Ixbg0XXgck+Hq4O9k=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
|
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
|
|
@ -520,18 +428,14 @@ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYr
|
||||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
|
||||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||||
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pressly/goose v2.7.0+incompatible h1:PWejVEv07LCerQEzMMeAtjuyCKbyprZ/LBa6K5P0OCQ=
|
|
||||||
github.com/pressly/goose v2.7.0+incompatible/go.mod h1:m+QHWCqxR3k8D9l7qfzuC/djtlfzxr34mozWDYEu1z8=
|
|
||||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
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 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.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
|
|
@ -563,9 +467,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
||||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
|
||||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
||||||
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
|
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
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/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||||
|
|
@ -587,7 +489,6 @@ github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b
|
||||||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
||||||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
|
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
|
||||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
|
||||||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
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/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.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
|
@ -598,15 +499,9 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
|
||||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
|
||||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
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.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||||
|
|
@ -636,30 +531,16 @@ github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVK
|
||||||
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
|
||||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
|
||||||
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
|
||||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
|
||||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
|
||||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
|
||||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
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/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
||||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||||
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
|
||||||
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
|
|
||||||
github.com/yggdrasil-network/yggdrasil-go v0.4.3 h1:LNS7kNpKzFlxQ9xmD5tfmMEvzwa+utBoD6pV9t2a8q4=
|
github.com/yggdrasil-network/yggdrasil-go v0.4.3 h1:LNS7kNpKzFlxQ9xmD5tfmMEvzwa+utBoD6pV9t2a8q4=
|
||||||
github.com/yggdrasil-network/yggdrasil-go v0.4.3/go.mod h1:A1/8kOQT7vzBxlkQtLf1KzJR0cbfL/2zjOCiYOAdjjo=
|
github.com/yggdrasil-network/yggdrasil-go v0.4.3/go.mod h1:A1/8kOQT7vzBxlkQtLf1KzJR0cbfL/2zjOCiYOAdjjo=
|
||||||
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
|
|
||||||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
|
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
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.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
|
@ -677,26 +558,20 @@ go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
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/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||||
golang.org/x/crypto v0.0.0-20180214000028-650f4a345ab4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
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-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-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-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-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-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
|
||||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
|
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
|
||||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
|
@ -741,21 +616,19 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
||||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/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.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20180406214816-61147c48b25b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
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-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-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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-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-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-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-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/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-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-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
|
@ -764,7 +637,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-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-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/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-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-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
|
@ -781,7 +653,6 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
|
||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
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-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-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73/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-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-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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
|
|
@ -790,10 +661,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210927181540-4e4d966f7476/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210927181540-4e4d966f7476/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211101193420-4a448f8816b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211101193420-4a448f8816b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20220524220425-1d687d428aca h1:xTaFYiPROfpPhqrfTIDXj0ri1SpfueYT951s4bAuDO8=
|
golang.org/x/net v0.0.0-20220524220425-1d687d428aca h1:xTaFYiPROfpPhqrfTIDXj0ri1SpfueYT951s4bAuDO8=
|
||||||
golang.org/x/net v0.0.0-20220524220425-1d687d428aca/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220524220425-1d687d428aca/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
|
@ -821,10 +690,8 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-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-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/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-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-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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|
@ -834,9 +701,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|
@ -884,14 +749,11 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/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-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/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-20220111092808-5a964db01320/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-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
|
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
|
||||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
|
@ -900,29 +762,24 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/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.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0=
|
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0=
|
||||||
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
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-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-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/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
|
||||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
|
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
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-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-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/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-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-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-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-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
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-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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
|
@ -965,8 +822,9 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||||
golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098 h1:YuekqPskqwCCPM79F1X5Dhv4ezTCj+Ki1oNwiafxkA0=
|
|
||||||
golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||||
|
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
||||||
|
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|
@ -1071,32 +929,22 @@ google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+Rur
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
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 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/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-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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
|
||||||
gopkg.in/errgo.v1 v1.0.0-20161222125816-442357a80af5/go.mod h1:u0ALmqvLRxLI95fkdCEWrE6mhWYZW1aMOJHp5YXLHTg=
|
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/h2non/bimg.v1 v1.1.9 h1:wZIUbeOnwr37Ta4aofhIv8OI8v4ujpjXC9mXnAGpQjM=
|
gopkg.in/h2non/bimg.v1 v1.1.9 h1:wZIUbeOnwr37Ta4aofhIv8OI8v4ujpjXC9mXnAGpQjM=
|
||||||
gopkg.in/h2non/bimg.v1 v1.1.9/go.mod h1:PgsZL7dLwUbsGm1NYps320GxGgvQNTnecMCZqxV11So=
|
gopkg.in/h2non/bimg.v1 v1.1.9/go.mod h1:PgsZL7dLwUbsGm1NYps320GxGgvQNTnecMCZqxV11So=
|
||||||
gopkg.in/h2non/gock.v1 v1.0.14 h1:fTeu9fcUvSnLNacYvYI54h+1/XEteDyHvrVCZEEEYNM=
|
gopkg.in/h2non/gock.v1 v1.0.14 h1:fTeu9fcUvSnLNacYvYI54h+1/XEteDyHvrVCZEEEYNM=
|
||||||
gopkg.in/h2non/gock.v1 v1.0.14/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
gopkg.in/h2non/gock.v1 v1.0.14/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
||||||
gopkg.in/httprequest.v1 v1.1.1/go.mod h1:/CkavNL+g3qLOrpFHVrEx4NKepeqR4XTZWNj4sGGjz0=
|
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|
||||||
gopkg.in/macaroon.v2 v2.1.0 h1:HZcsjBCzq9t0eBPMKqTN/uSN6JOm78ZJ2INbqcBQOUI=
|
gopkg.in/macaroon.v2 v2.1.0 h1:HZcsjBCzq9t0eBPMKqTN/uSN6JOm78ZJ2INbqcBQOUI=
|
||||||
gopkg.in/macaroon.v2 v2.1.0/go.mod h1:OUb+TQP/OP0WOerC2Jp/3CwhIKyIa9kQjuc7H24e6/o=
|
gopkg.in/macaroon.v2 v2.1.0/go.mod h1:OUb+TQP/OP0WOerC2Jp/3CwhIKyIa9kQjuc7H24e6/o=
|
||||||
gopkg.in/mgo.v2 v2.0.0-20160818015218-f2b6f6c918c4/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
|
||||||
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
|
||||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=
|
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170712054546-1be3d31502d6/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
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.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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|
@ -1105,7 +953,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
|
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
|
||||||
|
|
@ -1122,8 +969,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
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.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.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM=
|
|
||||||
launchpad.net/xmlpath v0.0.0-20130614043138-000000000004/go.mod h1:vqyExLOM3qBx7mvYRkoxjSCF945s0mbe7YynlKYXtsA=
|
|
||||||
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
|
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
|
||||||
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
|
|
||||||
18
internal/caching/cache_eventstatekeys.go
Normal file
18
internal/caching/cache_eventstatekeys.go
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
package caching
|
||||||
|
|
||||||
|
import "github.com/matrix-org/dendrite/roomserver/types"
|
||||||
|
|
||||||
|
// EventStateKeyCache contains the subset of functions needed for
|
||||||
|
// a room event state key cache.
|
||||||
|
type EventStateKeyCache interface {
|
||||||
|
GetEventStateKey(eventStateKeyNID types.EventStateKeyNID) (string, bool)
|
||||||
|
StoreEventStateKey(eventStateKeyNID types.EventStateKeyNID, eventStateKey string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Caches) GetEventStateKey(eventStateKeyNID types.EventStateKeyNID) (string, bool) {
|
||||||
|
return c.RoomServerStateKeys.Get(eventStateKeyNID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Caches) StoreEventStateKey(eventStateKeyNID types.EventStateKeyNID, eventStateKey string) {
|
||||||
|
c.RoomServerStateKeys.Set(eventStateKeyNID, eventStateKey)
|
||||||
|
}
|
||||||
|
|
@ -1,18 +1,9 @@
|
||||||
package caching
|
package caching
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
FederationEventCacheName = "federation_event"
|
|
||||||
FederationEventCacheMaxEntries = 256
|
|
||||||
FederationEventCacheMutable = true // to allow use of Unset only
|
|
||||||
FederationEventCacheMaxAge = CacheNoMaxAge
|
|
||||||
)
|
|
||||||
|
|
||||||
// FederationCache contains the subset of functions needed for
|
// FederationCache contains the subset of functions needed for
|
||||||
// a federation event cache.
|
// a federation event cache.
|
||||||
type FederationCache interface {
|
type FederationCache interface {
|
||||||
|
|
@ -26,43 +17,25 @@ type FederationCache interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) GetFederationQueuedPDU(eventNID int64) (*gomatrixserverlib.HeaderedEvent, bool) {
|
func (c Caches) GetFederationQueuedPDU(eventNID int64) (*gomatrixserverlib.HeaderedEvent, bool) {
|
||||||
key := fmt.Sprintf("%d", eventNID)
|
return c.FederationPDUs.Get(eventNID)
|
||||||
val, found := c.FederationEvents.Get(key)
|
|
||||||
if found && val != nil {
|
|
||||||
if event, ok := val.(*gomatrixserverlib.HeaderedEvent); ok {
|
|
||||||
return event, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) StoreFederationQueuedPDU(eventNID int64, event *gomatrixserverlib.HeaderedEvent) {
|
func (c Caches) StoreFederationQueuedPDU(eventNID int64, event *gomatrixserverlib.HeaderedEvent) {
|
||||||
key := fmt.Sprintf("%d", eventNID)
|
c.FederationPDUs.Set(eventNID, event)
|
||||||
c.FederationEvents.Set(key, event)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) EvictFederationQueuedPDU(eventNID int64) {
|
func (c Caches) EvictFederationQueuedPDU(eventNID int64) {
|
||||||
key := fmt.Sprintf("%d", eventNID)
|
c.FederationPDUs.Unset(eventNID)
|
||||||
c.FederationEvents.Unset(key)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) GetFederationQueuedEDU(eventNID int64) (*gomatrixserverlib.EDU, bool) {
|
func (c Caches) GetFederationQueuedEDU(eventNID int64) (*gomatrixserverlib.EDU, bool) {
|
||||||
key := fmt.Sprintf("%d", eventNID)
|
return c.FederationEDUs.Get(eventNID)
|
||||||
val, found := c.FederationEvents.Get(key)
|
|
||||||
if found && val != nil {
|
|
||||||
if event, ok := val.(*gomatrixserverlib.EDU); ok {
|
|
||||||
return event, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) StoreFederationQueuedEDU(eventNID int64, event *gomatrixserverlib.EDU) {
|
func (c Caches) StoreFederationQueuedEDU(eventNID int64, event *gomatrixserverlib.EDU) {
|
||||||
key := fmt.Sprintf("%d", eventNID)
|
c.FederationEDUs.Set(eventNID, event)
|
||||||
c.FederationEvents.Set(key, event)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) EvictFederationQueuedEDU(eventNID int64) {
|
func (c Caches) EvictFederationQueuedEDU(eventNID int64) {
|
||||||
key := fmt.Sprintf("%d", eventNID)
|
c.FederationEDUs.Unset(eventNID)
|
||||||
c.FederationEvents.Unset(key)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,67 +1,35 @@
|
||||||
package caching
|
package caching
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
type lazyLoadingCacheKey struct {
|
||||||
LazyLoadCacheName = "lazy_load_members"
|
UserID string // the user we're querying on behalf of
|
||||||
LazyLoadCacheMaxEntries = 128
|
DeviceID string // the user we're querying on behalf of
|
||||||
LazyLoadCacheMaxUserEntries = 128
|
RoomID string // the room in question
|
||||||
LazyLoadCacheMutable = true
|
TargetUserID string // the user whose membership we're asking about
|
||||||
LazyLoadCacheMaxAge = time.Minute * 30
|
}
|
||||||
)
|
|
||||||
|
|
||||||
type LazyLoadCache interface {
|
type LazyLoadCache interface {
|
||||||
StoreLazyLoadedUser(device *userapi.Device, roomID, userID, eventID string)
|
StoreLazyLoadedUser(device *userapi.Device, roomID, userID, eventID string)
|
||||||
IsLazyLoadedUserCached(device *userapi.Device, roomID, userID string) (string, bool)
|
IsLazyLoadedUserCached(device *userapi.Device, roomID, userID string) (string, bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) lazyLoadCacheForUser(device *userapi.Device) (*InMemoryLRUCachePartition, error) {
|
|
||||||
cacheName := fmt.Sprintf("%s/%s", device.UserID, device.ID)
|
|
||||||
userCache, ok := c.LazyLoading.Get(cacheName)
|
|
||||||
if ok && userCache != nil {
|
|
||||||
if cache, ok := userCache.(*InMemoryLRUCachePartition); ok {
|
|
||||||
return cache, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cache, err := NewInMemoryLRUCachePartition(
|
|
||||||
LazyLoadCacheName,
|
|
||||||
LazyLoadCacheMutable,
|
|
||||||
LazyLoadCacheMaxUserEntries,
|
|
||||||
LazyLoadCacheMaxAge,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c.LazyLoading.Set(cacheName, cache)
|
|
||||||
go cacheCleaner(cache)
|
|
||||||
return cache, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Caches) StoreLazyLoadedUser(device *userapi.Device, roomID, userID, eventID string) {
|
func (c Caches) StoreLazyLoadedUser(device *userapi.Device, roomID, userID, eventID string) {
|
||||||
cache, err := c.lazyLoadCacheForUser(device)
|
c.LazyLoading.Set(lazyLoadingCacheKey{
|
||||||
if err != nil {
|
UserID: device.UserID,
|
||||||
return
|
DeviceID: device.ID,
|
||||||
}
|
RoomID: roomID,
|
||||||
cacheKey := fmt.Sprintf("%s/%s/%s/%s", device.UserID, device.ID, roomID, userID)
|
TargetUserID: userID,
|
||||||
cache.Set(cacheKey, eventID)
|
}, eventID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) IsLazyLoadedUserCached(device *userapi.Device, roomID, userID string) (string, bool) {
|
func (c Caches) IsLazyLoadedUserCached(device *userapi.Device, roomID, userID string) (string, bool) {
|
||||||
cache, err := c.lazyLoadCacheForUser(device)
|
return c.LazyLoading.Get(lazyLoadingCacheKey{
|
||||||
if err != nil {
|
UserID: device.UserID,
|
||||||
return "", false
|
DeviceID: device.ID,
|
||||||
}
|
RoomID: roomID,
|
||||||
|
TargetUserID: userID,
|
||||||
cacheKey := fmt.Sprintf("%s/%s/%s/%s", device.UserID, device.ID, roomID, userID)
|
})
|
||||||
val, ok := cache.Get(cacheKey)
|
|
||||||
if !ok {
|
|
||||||
return "", ok
|
|
||||||
}
|
|
||||||
return val.(string), ok
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
21
internal/caching/cache_roomevents.go
Normal file
21
internal/caching/cache_roomevents.go
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
package caching
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RoomServerEventsCache contains the subset of functions needed for
|
||||||
|
// a roomserver event cache.
|
||||||
|
type RoomServerEventsCache interface {
|
||||||
|
GetRoomServerEvent(eventNID types.EventNID) (*gomatrixserverlib.Event, bool)
|
||||||
|
StoreRoomServerEvent(eventNID types.EventNID, event *gomatrixserverlib.Event)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Caches) GetRoomServerEvent(eventNID types.EventNID) (*gomatrixserverlib.Event, bool) {
|
||||||
|
return c.RoomServerEvents.Get(int64(eventNID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Caches) StoreRoomServerEvent(eventNID types.EventNID, event *gomatrixserverlib.Event) {
|
||||||
|
c.RoomServerEvents.Set(int64(eventNID), event)
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package caching
|
package caching
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -14,35 +12,22 @@ import (
|
||||||
// used from other components as we currently have no way to invalidate
|
// used from other components as we currently have no way to invalidate
|
||||||
// the cache in downstream components.
|
// the cache in downstream components.
|
||||||
|
|
||||||
const (
|
|
||||||
RoomInfoCacheName = "roominfo"
|
|
||||||
RoomInfoCacheMaxEntries = 1024
|
|
||||||
RoomInfoCacheMutable = true
|
|
||||||
RoomInfoCacheMaxAge = time.Minute * 5
|
|
||||||
)
|
|
||||||
|
|
||||||
// RoomInfosCache contains the subset of functions needed for
|
// RoomInfosCache contains the subset of functions needed for
|
||||||
// a room Info cache. It must only be used from the roomserver only
|
// a room Info cache. It must only be used from the roomserver only
|
||||||
// It is not safe for use from other components.
|
// It is not safe for use from other components.
|
||||||
type RoomInfoCache interface {
|
type RoomInfoCache interface {
|
||||||
GetRoomInfo(roomID string) (roomInfo types.RoomInfo, ok bool)
|
GetRoomInfo(roomID string) (roomInfo *types.RoomInfo, ok bool)
|
||||||
StoreRoomInfo(roomID string, roomInfo types.RoomInfo)
|
StoreRoomInfo(roomID string, roomInfo *types.RoomInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRoomInfo must only be called from the roomserver only. It is not
|
// GetRoomInfo must only be called from the roomserver only. It is not
|
||||||
// safe for use from other components.
|
// safe for use from other components.
|
||||||
func (c Caches) GetRoomInfo(roomID string) (types.RoomInfo, bool) {
|
func (c Caches) GetRoomInfo(roomID string) (*types.RoomInfo, bool) {
|
||||||
val, found := c.RoomInfos.Get(roomID)
|
return c.RoomInfos.Get(roomID)
|
||||||
if found && val != nil {
|
|
||||||
if roomInfo, ok := val.(types.RoomInfo); ok {
|
|
||||||
return roomInfo, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return types.RoomInfo{}, false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StoreRoomInfo must only be called from the roomserver only. It is not
|
// StoreRoomInfo must only be called from the roomserver only. It is not
|
||||||
// safe for use from other components.
|
// safe for use from other components.
|
||||||
func (c Caches) StoreRoomInfo(roomID string, roomInfo types.RoomInfo) {
|
func (c Caches) StoreRoomInfo(roomID string, roomInfo *types.RoomInfo) {
|
||||||
c.RoomInfos.Set(roomID, roomInfo)
|
c.RoomInfos.Set(roomID, roomInfo)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,15 @@
|
||||||
package caching
|
package caching
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
RoomServerRoomIDsCacheName = "roomserver_room_ids"
|
|
||||||
RoomServerRoomIDsCacheMaxEntries = 1024
|
|
||||||
RoomServerRoomIDsCacheMutable = false
|
|
||||||
RoomServerRoomIDsCacheMaxAge = CacheNoMaxAge
|
|
||||||
)
|
|
||||||
|
|
||||||
type RoomServerCaches interface {
|
type RoomServerCaches interface {
|
||||||
RoomServerNIDsCache
|
RoomServerNIDsCache
|
||||||
RoomVersionCache
|
RoomVersionCache
|
||||||
RoomInfoCache
|
RoomInfoCache
|
||||||
|
RoomServerEventsCache
|
||||||
|
EventStateKeyCache
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoomServerNIDsCache contains the subset of functions needed for
|
// RoomServerNIDsCache contains the subset of functions needed for
|
||||||
|
|
@ -27,15 +20,9 @@ type RoomServerNIDsCache interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) GetRoomServerRoomID(roomNID types.RoomNID) (string, bool) {
|
func (c Caches) GetRoomServerRoomID(roomNID types.RoomNID) (string, bool) {
|
||||||
val, found := c.RoomServerRoomIDs.Get(strconv.Itoa(int(roomNID)))
|
return c.RoomServerRoomIDs.Get(roomNID)
|
||||||
if found && val != nil {
|
|
||||||
if roomID, ok := val.(string); ok {
|
|
||||||
return roomID, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) StoreRoomServerRoomID(roomNID types.RoomNID, roomID string) {
|
func (c Caches) StoreRoomServerRoomID(roomNID types.RoomNID, roomID string) {
|
||||||
c.RoomServerRoomIDs.Set(strconv.Itoa(int(roomNID)), roomID)
|
c.RoomServerRoomIDs.Set(roomNID, roomID)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,6 @@ package caching
|
||||||
|
|
||||||
import "github.com/matrix-org/gomatrixserverlib"
|
import "github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
||||||
const (
|
|
||||||
RoomVersionCacheName = "room_versions"
|
|
||||||
RoomVersionCacheMaxEntries = 1024
|
|
||||||
RoomVersionCacheMutable = false
|
|
||||||
RoomVersionCacheMaxAge = CacheNoMaxAge
|
|
||||||
)
|
|
||||||
|
|
||||||
// RoomVersionsCache contains the subset of functions needed for
|
// RoomVersionsCache contains the subset of functions needed for
|
||||||
// a room version cache.
|
// a room version cache.
|
||||||
type RoomVersionCache interface {
|
type RoomVersionCache interface {
|
||||||
|
|
@ -17,13 +10,7 @@ type RoomVersionCache interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) GetRoomVersion(roomID string) (gomatrixserverlib.RoomVersion, bool) {
|
func (c Caches) GetRoomVersion(roomID string) (gomatrixserverlib.RoomVersion, bool) {
|
||||||
val, found := c.RoomVersions.Get(roomID)
|
return c.RoomVersions.Get(roomID)
|
||||||
if found && val != nil {
|
|
||||||
if roomVersion, ok := val.(gomatrixserverlib.RoomVersion); ok {
|
|
||||||
return roomVersion, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) StoreRoomVersion(roomID string, roomVersion gomatrixserverlib.RoomVersion) {
|
func (c Caches) StoreRoomVersion(roomID string, roomVersion gomatrixserverlib.RoomVersion) {
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,6 @@ import (
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
ServerKeyCacheName = "server_key"
|
|
||||||
ServerKeyCacheMaxEntries = 4096
|
|
||||||
ServerKeyCacheMutable = true
|
|
||||||
ServerKeyCacheMaxAge = CacheNoMaxAge
|
|
||||||
)
|
|
||||||
|
|
||||||
// ServerKeyCache contains the subset of functions needed for
|
// ServerKeyCache contains the subset of functions needed for
|
||||||
// a server key cache.
|
// a server key cache.
|
||||||
type ServerKeyCache interface {
|
type ServerKeyCache interface {
|
||||||
|
|
@ -34,18 +27,13 @@ func (c Caches) GetServerKey(
|
||||||
) (gomatrixserverlib.PublicKeyLookupResult, bool) {
|
) (gomatrixserverlib.PublicKeyLookupResult, bool) {
|
||||||
key := fmt.Sprintf("%s/%s", request.ServerName, request.KeyID)
|
key := fmt.Sprintf("%s/%s", request.ServerName, request.KeyID)
|
||||||
val, found := c.ServerKeys.Get(key)
|
val, found := c.ServerKeys.Get(key)
|
||||||
if found && val != nil {
|
if found && !val.WasValidAt(timestamp, true) {
|
||||||
if keyLookupResult, ok := val.(gomatrixserverlib.PublicKeyLookupResult); ok {
|
// The key wasn't valid at the requested timestamp so don't
|
||||||
if !keyLookupResult.WasValidAt(timestamp, true) {
|
// return it. The caller will have to work out what to do.
|
||||||
// The key wasn't valid at the requested timestamp so don't
|
c.ServerKeys.Unset(key)
|
||||||
// return it. The caller will have to work out what to do.
|
return gomatrixserverlib.PublicKeyLookupResult{}, false
|
||||||
c.ServerKeys.Unset(key)
|
|
||||||
return gomatrixserverlib.PublicKeyLookupResult{}, false
|
|
||||||
}
|
|
||||||
return keyLookupResult, true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return gomatrixserverlib.PublicKeyLookupResult{}, false
|
return val, found
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) StoreServerKey(
|
func (c Caches) StoreServerKey(
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,16 @@
|
||||||
package caching
|
package caching
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
SpaceSummaryRoomsCacheName = "space_summary_rooms"
|
|
||||||
SpaceSummaryRoomsCacheMaxEntries = 100
|
|
||||||
SpaceSummaryRoomsCacheMutable = true
|
|
||||||
SpaceSummaryRoomsCacheMaxAge = time.Minute * 5
|
|
||||||
)
|
|
||||||
|
|
||||||
type SpaceSummaryRoomsCache interface {
|
type SpaceSummaryRoomsCache interface {
|
||||||
GetSpaceSummary(roomID string) (r gomatrixserverlib.MSC2946SpacesResponse, ok bool)
|
GetSpaceSummary(roomID string) (r gomatrixserverlib.MSC2946SpacesResponse, ok bool)
|
||||||
StoreSpaceSummary(roomID string, r gomatrixserverlib.MSC2946SpacesResponse)
|
StoreSpaceSummary(roomID string, r gomatrixserverlib.MSC2946SpacesResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) GetSpaceSummary(roomID string) (r gomatrixserverlib.MSC2946SpacesResponse, ok bool) {
|
func (c Caches) GetSpaceSummary(roomID string) (r gomatrixserverlib.MSC2946SpacesResponse, ok bool) {
|
||||||
val, found := c.SpaceSummaryRooms.Get(roomID)
|
return c.SpaceSummaryRooms.Get(roomID)
|
||||||
if found && val != nil {
|
|
||||||
if resp, ok := val.(gomatrixserverlib.MSC2946SpacesResponse); ok {
|
|
||||||
return resp, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r, false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Caches) StoreSpaceSummary(roomID string, r gomatrixserverlib.MSC2946SpacesResponse) {
|
func (c Caches) StoreSpaceSummary(roomID string, r gomatrixserverlib.MSC2946SpacesResponse) {
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,53 @@
|
||||||
|
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package caching
|
package caching
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Caches contains a set of references to caches. They may be
|
// Caches contains a set of references to caches. They may be
|
||||||
// different implementations as long as they satisfy the Cache
|
// different implementations as long as they satisfy the Cache
|
||||||
// interface.
|
// interface.
|
||||||
type Caches struct {
|
type Caches struct {
|
||||||
RoomVersions Cache // RoomVersionCache
|
RoomVersions Cache[string, gomatrixserverlib.RoomVersion] // room ID -> room version
|
||||||
ServerKeys Cache // ServerKeyCache
|
ServerKeys Cache[string, gomatrixserverlib.PublicKeyLookupResult] // server name -> server keys
|
||||||
RoomServerRoomNIDs Cache // RoomServerNIDsCache
|
RoomServerRoomNIDs Cache[string, types.RoomNID] // room ID -> room NID
|
||||||
RoomServerRoomIDs Cache // RoomServerNIDsCache
|
RoomServerRoomIDs Cache[types.RoomNID, string] // room NID -> room ID
|
||||||
RoomInfos Cache // RoomInfoCache
|
RoomServerEvents Cache[int64, *gomatrixserverlib.Event] // event NID -> event
|
||||||
FederationEvents Cache // FederationEventsCache
|
RoomServerStateKeys Cache[types.EventStateKeyNID, string] // event NID -> event state key
|
||||||
SpaceSummaryRooms Cache // SpaceSummaryRoomsCache
|
RoomInfos Cache[string, *types.RoomInfo] // room ID -> room info
|
||||||
LazyLoading Cache // LazyLoadCache
|
FederationPDUs Cache[int64, *gomatrixserverlib.HeaderedEvent] // queue NID -> PDU
|
||||||
|
FederationEDUs Cache[int64, *gomatrixserverlib.EDU] // queue NID -> EDU
|
||||||
|
SpaceSummaryRooms Cache[string, gomatrixserverlib.MSC2946SpacesResponse] // room ID -> space response
|
||||||
|
LazyLoading Cache[lazyLoadingCacheKey, string] // composite key -> event ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache is the interface that an implementation must satisfy.
|
// Cache is the interface that an implementation must satisfy.
|
||||||
type Cache interface {
|
type Cache[K keyable, T any] interface {
|
||||||
Get(key string) (value interface{}, ok bool)
|
Get(key K) (value T, ok bool)
|
||||||
Set(key string, value interface{})
|
Set(key K, value T)
|
||||||
Unset(key string)
|
Unset(key K)
|
||||||
}
|
}
|
||||||
|
|
||||||
const CacheNoMaxAge = time.Duration(0)
|
type keyable interface {
|
||||||
|
// from https://github.com/dgraph-io/ristretto/blob/8e850b710d6df0383c375ec6a7beae4ce48fc8d5/z/z.go#L34
|
||||||
|
~uint64 | ~string | []byte | byte | ~int | ~int32 | ~uint32 | ~int64 | lazyLoadingCacheKey
|
||||||
|
}
|
||||||
|
|
||||||
|
type costable interface {
|
||||||
|
CacheCost() int
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,189 +0,0 @@
|
||||||
package caching
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewInMemoryLRUCache(enablePrometheus bool) (*Caches, error) {
|
|
||||||
roomVersions, err := NewInMemoryLRUCachePartition(
|
|
||||||
RoomVersionCacheName,
|
|
||||||
RoomVersionCacheMutable,
|
|
||||||
RoomVersionCacheMaxEntries,
|
|
||||||
RoomVersionCacheMaxAge,
|
|
||||||
enablePrometheus,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
serverKeys, err := NewInMemoryLRUCachePartition(
|
|
||||||
ServerKeyCacheName,
|
|
||||||
ServerKeyCacheMutable,
|
|
||||||
ServerKeyCacheMaxEntries,
|
|
||||||
ServerKeyCacheMaxAge,
|
|
||||||
enablePrometheus,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
roomServerRoomIDs, err := NewInMemoryLRUCachePartition(
|
|
||||||
RoomServerRoomIDsCacheName,
|
|
||||||
RoomServerRoomIDsCacheMutable,
|
|
||||||
RoomServerRoomIDsCacheMaxEntries,
|
|
||||||
RoomServerRoomIDsCacheMaxAge,
|
|
||||||
enablePrometheus,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
roomInfos, err := NewInMemoryLRUCachePartition(
|
|
||||||
RoomInfoCacheName,
|
|
||||||
RoomInfoCacheMutable,
|
|
||||||
RoomInfoCacheMaxEntries,
|
|
||||||
RoomInfoCacheMaxAge,
|
|
||||||
enablePrometheus,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
federationEvents, err := NewInMemoryLRUCachePartition(
|
|
||||||
FederationEventCacheName,
|
|
||||||
FederationEventCacheMutable,
|
|
||||||
FederationEventCacheMaxEntries,
|
|
||||||
FederationEventCacheMaxAge,
|
|
||||||
enablePrometheus,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
spaceRooms, err := NewInMemoryLRUCachePartition(
|
|
||||||
SpaceSummaryRoomsCacheName,
|
|
||||||
SpaceSummaryRoomsCacheMutable,
|
|
||||||
SpaceSummaryRoomsCacheMaxEntries,
|
|
||||||
SpaceSummaryRoomsCacheMaxAge,
|
|
||||||
enablePrometheus,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
lazyLoadCache, err := NewInMemoryLRUCachePartition(
|
|
||||||
LazyLoadCacheName,
|
|
||||||
LazyLoadCacheMutable,
|
|
||||||
LazyLoadCacheMaxEntries,
|
|
||||||
LazyLoadCacheMaxAge,
|
|
||||||
enablePrometheus,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
go cacheCleaner(
|
|
||||||
roomVersions, serverKeys, roomServerRoomIDs,
|
|
||||||
roomInfos, federationEvents, spaceRooms, lazyLoadCache,
|
|
||||||
)
|
|
||||||
return &Caches{
|
|
||||||
RoomVersions: roomVersions,
|
|
||||||
ServerKeys: serverKeys,
|
|
||||||
RoomServerRoomIDs: roomServerRoomIDs,
|
|
||||||
RoomInfos: roomInfos,
|
|
||||||
FederationEvents: federationEvents,
|
|
||||||
SpaceSummaryRooms: spaceRooms,
|
|
||||||
LazyLoading: lazyLoadCache,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cacheCleaner(caches ...*InMemoryLRUCachePartition) {
|
|
||||||
for {
|
|
||||||
time.Sleep(time.Minute)
|
|
||||||
for _, cache := range caches {
|
|
||||||
// Hold onto the last 10% of the cache entries, since
|
|
||||||
// otherwise a quiet period might cause us to evict all
|
|
||||||
// cache entries entirely.
|
|
||||||
if cache.lru.Len() > cache.maxEntries/10 {
|
|
||||||
cache.lru.RemoveOldest()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type InMemoryLRUCachePartition struct {
|
|
||||||
name string
|
|
||||||
mutable bool
|
|
||||||
maxEntries int
|
|
||||||
maxAge time.Duration
|
|
||||||
lru *lru.Cache
|
|
||||||
}
|
|
||||||
|
|
||||||
type inMemoryLRUCacheEntry struct {
|
|
||||||
value interface{}
|
|
||||||
created time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewInMemoryLRUCachePartition(name string, mutable bool, maxEntries int, maxAge time.Duration, enablePrometheus bool) (*InMemoryLRUCachePartition, error) {
|
|
||||||
var err error
|
|
||||||
cache := InMemoryLRUCachePartition{
|
|
||||||
name: name,
|
|
||||||
mutable: mutable,
|
|
||||||
maxEntries: maxEntries,
|
|
||||||
maxAge: maxAge,
|
|
||||||
}
|
|
||||||
cache.lru, err = lru.New(maxEntries)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if enablePrometheus {
|
|
||||||
promauto.NewGaugeFunc(prometheus.GaugeOpts{
|
|
||||||
Namespace: "dendrite",
|
|
||||||
Subsystem: "caching_in_memory_lru",
|
|
||||||
Name: name,
|
|
||||||
}, func() float64 {
|
|
||||||
return float64(cache.lru.Len())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return &cache, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *InMemoryLRUCachePartition) Set(key string, value interface{}) {
|
|
||||||
if !c.mutable {
|
|
||||||
if peek, ok := c.lru.Peek(key); ok {
|
|
||||||
if entry, ok := peek.(*inMemoryLRUCacheEntry); ok && entry.value != value {
|
|
||||||
panic(fmt.Sprintf("invalid use of immutable cache tries to mutate existing value of %q", key))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.lru.Add(key, &inMemoryLRUCacheEntry{
|
|
||||||
value: value,
|
|
||||||
created: time.Now(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *InMemoryLRUCachePartition) Unset(key string) {
|
|
||||||
if !c.mutable {
|
|
||||||
panic(fmt.Sprintf("invalid use of immutable cache tries to unset value of %q", key))
|
|
||||||
}
|
|
||||||
c.lru.Remove(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *InMemoryLRUCachePartition) Get(key string) (value interface{}, ok bool) {
|
|
||||||
v, ok := c.lru.Get(key)
|
|
||||||
if !ok {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
entry, ok := v.(*inMemoryLRUCacheEntry)
|
|
||||||
switch {
|
|
||||||
case ok && c.maxAge == CacheNoMaxAge:
|
|
||||||
return entry.value, ok // There's no maximum age policy
|
|
||||||
case ok && time.Since(entry.created) < c.maxAge:
|
|
||||||
return entry.value, ok // The value for the key isn't stale
|
|
||||||
default:
|
|
||||||
// Either the key was found and it was stale, or the key
|
|
||||||
// wasn't found at all
|
|
||||||
c.lru.Remove(key)
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
206
internal/caching/impl_ristretto.go
Normal file
206
internal/caching/impl_ristretto.go
Normal file
|
|
@ -0,0 +1,206 @@
|
||||||
|
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package caching
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/dgraph-io/ristretto"
|
||||||
|
"github.com/dgraph-io/ristretto/z"
|
||||||
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
roomVersionsCache byte = iota + 1
|
||||||
|
serverKeysCache
|
||||||
|
roomNIDsCache
|
||||||
|
roomIDsCache
|
||||||
|
roomEventsCache
|
||||||
|
roomInfosCache
|
||||||
|
federationPDUsCache
|
||||||
|
federationEDUsCache
|
||||||
|
spaceSummaryRoomsCache
|
||||||
|
lazyLoadingCache
|
||||||
|
eventStateKeyCache
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewRistrettoCache(maxCost config.DataUnit, maxAge time.Duration, enablePrometheus bool) *Caches {
|
||||||
|
cache, err := ristretto.NewCache(&ristretto.Config{
|
||||||
|
NumCounters: int64((maxCost / 1024) * 10), // 10 counters per 1KB data, affects bloom filter size
|
||||||
|
BufferItems: 64, // recommended by the ristretto godocs as a sane buffer size value
|
||||||
|
MaxCost: int64(maxCost), // max cost is in bytes, as per the Dendrite config
|
||||||
|
Metrics: true,
|
||||||
|
KeyToHash: func(key interface{}) (uint64, uint64) {
|
||||||
|
return z.KeyToHash(key)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if enablePrometheus {
|
||||||
|
promauto.NewGaugeFunc(prometheus.GaugeOpts{
|
||||||
|
Namespace: "dendrite",
|
||||||
|
Subsystem: "caching_ristretto",
|
||||||
|
Name: "ratio",
|
||||||
|
}, func() float64 {
|
||||||
|
return float64(cache.Metrics.Ratio())
|
||||||
|
})
|
||||||
|
promauto.NewGaugeFunc(prometheus.GaugeOpts{
|
||||||
|
Namespace: "dendrite",
|
||||||
|
Subsystem: "caching_ristretto",
|
||||||
|
Name: "cost",
|
||||||
|
}, func() float64 {
|
||||||
|
return float64(cache.Metrics.CostAdded() - cache.Metrics.CostEvicted())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return &Caches{
|
||||||
|
RoomVersions: &RistrettoCachePartition[string, gomatrixserverlib.RoomVersion]{ // room ID -> room version
|
||||||
|
cache: cache,
|
||||||
|
Prefix: roomVersionsCache,
|
||||||
|
MaxAge: maxAge,
|
||||||
|
},
|
||||||
|
ServerKeys: &RistrettoCachePartition[string, gomatrixserverlib.PublicKeyLookupResult]{ // server name -> server keys
|
||||||
|
cache: cache,
|
||||||
|
Prefix: serverKeysCache,
|
||||||
|
Mutable: true,
|
||||||
|
MaxAge: maxAge,
|
||||||
|
},
|
||||||
|
RoomServerRoomNIDs: &RistrettoCachePartition[string, types.RoomNID]{ // room ID -> room NID
|
||||||
|
cache: cache,
|
||||||
|
Prefix: roomNIDsCache,
|
||||||
|
MaxAge: maxAge,
|
||||||
|
},
|
||||||
|
RoomServerRoomIDs: &RistrettoCachePartition[types.RoomNID, string]{ // room NID -> room ID
|
||||||
|
cache: cache,
|
||||||
|
Prefix: roomIDsCache,
|
||||||
|
MaxAge: maxAge,
|
||||||
|
},
|
||||||
|
RoomServerEvents: &RistrettoCostedCachePartition[int64, *gomatrixserverlib.Event]{ // event NID -> event
|
||||||
|
&RistrettoCachePartition[int64, *gomatrixserverlib.Event]{
|
||||||
|
cache: cache,
|
||||||
|
Prefix: roomEventsCache,
|
||||||
|
MaxAge: maxAge,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RoomServerStateKeys: &RistrettoCachePartition[types.EventStateKeyNID, string]{ // event NID -> event state key
|
||||||
|
cache: cache,
|
||||||
|
Prefix: eventStateKeyCache,
|
||||||
|
MaxAge: maxAge,
|
||||||
|
},
|
||||||
|
RoomInfos: &RistrettoCachePartition[string, *types.RoomInfo]{ // room ID -> room info
|
||||||
|
cache: cache,
|
||||||
|
Prefix: roomInfosCache,
|
||||||
|
Mutable: true,
|
||||||
|
MaxAge: maxAge,
|
||||||
|
},
|
||||||
|
FederationPDUs: &RistrettoCostedCachePartition[int64, *gomatrixserverlib.HeaderedEvent]{ // queue NID -> PDU
|
||||||
|
&RistrettoCachePartition[int64, *gomatrixserverlib.HeaderedEvent]{
|
||||||
|
cache: cache,
|
||||||
|
Prefix: federationPDUsCache,
|
||||||
|
Mutable: true,
|
||||||
|
MaxAge: lesserOf(time.Hour/2, maxAge),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
FederationEDUs: &RistrettoCostedCachePartition[int64, *gomatrixserverlib.EDU]{ // queue NID -> EDU
|
||||||
|
&RistrettoCachePartition[int64, *gomatrixserverlib.EDU]{
|
||||||
|
cache: cache,
|
||||||
|
Prefix: federationEDUsCache,
|
||||||
|
Mutable: true,
|
||||||
|
MaxAge: lesserOf(time.Hour/2, maxAge),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SpaceSummaryRooms: &RistrettoCachePartition[string, gomatrixserverlib.MSC2946SpacesResponse]{ // room ID -> space response
|
||||||
|
cache: cache,
|
||||||
|
Prefix: spaceSummaryRoomsCache,
|
||||||
|
Mutable: true,
|
||||||
|
MaxAge: maxAge,
|
||||||
|
},
|
||||||
|
LazyLoading: &RistrettoCachePartition[lazyLoadingCacheKey, string]{ // composite key -> event ID
|
||||||
|
cache: cache,
|
||||||
|
Prefix: lazyLoadingCache,
|
||||||
|
Mutable: true,
|
||||||
|
MaxAge: maxAge,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RistrettoCostedCachePartition[k keyable, v costable] struct {
|
||||||
|
*RistrettoCachePartition[k, v]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RistrettoCostedCachePartition[K, V]) Set(key K, value V) {
|
||||||
|
cost := value.CacheCost()
|
||||||
|
c.setWithCost(key, value, int64(cost))
|
||||||
|
}
|
||||||
|
|
||||||
|
type RistrettoCachePartition[K keyable, V any] struct {
|
||||||
|
cache *ristretto.Cache
|
||||||
|
Prefix byte
|
||||||
|
Mutable bool
|
||||||
|
MaxAge time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RistrettoCachePartition[K, V]) setWithCost(key K, value V, cost int64) {
|
||||||
|
bkey := fmt.Sprintf("%c%v", c.Prefix, key)
|
||||||
|
if !c.Mutable {
|
||||||
|
if v, ok := c.cache.Get(bkey); ok && v != nil && !reflect.DeepEqual(v, value) {
|
||||||
|
panic(fmt.Sprintf("invalid use of immutable cache tries to change value of %v from %v to %v", key, v, value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.cache.SetWithTTL(bkey, value, int64(len(bkey))+cost, c.MaxAge)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RistrettoCachePartition[K, V]) Set(key K, value V) {
|
||||||
|
var cost int64
|
||||||
|
if cv, ok := any(value).(string); ok {
|
||||||
|
cost = int64(len(cv))
|
||||||
|
} else {
|
||||||
|
cost = int64(unsafe.Sizeof(value))
|
||||||
|
}
|
||||||
|
c.setWithCost(key, value, cost)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RistrettoCachePartition[K, V]) Unset(key K) {
|
||||||
|
bkey := fmt.Sprintf("%c%v", c.Prefix, key)
|
||||||
|
if !c.Mutable {
|
||||||
|
panic(fmt.Sprintf("invalid use of immutable cache tries to unset value of %v", key))
|
||||||
|
}
|
||||||
|
c.cache.Del(bkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RistrettoCachePartition[K, V]) Get(key K) (value V, ok bool) {
|
||||||
|
bkey := fmt.Sprintf("%c%v", c.Prefix, key)
|
||||||
|
v, ok := c.cache.Get(bkey)
|
||||||
|
if !ok || v == nil {
|
||||||
|
var empty V
|
||||||
|
return empty, false
|
||||||
|
}
|
||||||
|
value, ok = v.(V)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func lesserOf(a, b time.Duration) time.Duration {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
@ -170,20 +170,18 @@ func truncateAuthAndPrevEvents(auth, prev []gomatrixserverlib.EventReference) (
|
||||||
|
|
||||||
// RedactEvent redacts the given event and sets the unsigned field appropriately. This should be used by
|
// RedactEvent redacts the given event and sets the unsigned field appropriately. This should be used by
|
||||||
// downstream components to the roomserver when an OutputTypeRedactedEvent occurs.
|
// downstream components to the roomserver when an OutputTypeRedactedEvent occurs.
|
||||||
func RedactEvent(redactionEvent, redactedEvent *gomatrixserverlib.Event) (*gomatrixserverlib.Event, error) {
|
func RedactEvent(redactionEvent, redactedEvent *gomatrixserverlib.Event) error {
|
||||||
// sanity check
|
// sanity check
|
||||||
if redactionEvent.Type() != gomatrixserverlib.MRoomRedaction {
|
if redactionEvent.Type() != gomatrixserverlib.MRoomRedaction {
|
||||||
return nil, fmt.Errorf("RedactEvent: redactionEvent isn't a redaction event, is '%s'", redactionEvent.Type())
|
return fmt.Errorf("RedactEvent: redactionEvent isn't a redaction event, is '%s'", redactionEvent.Type())
|
||||||
}
|
}
|
||||||
r := redactedEvent.Redact()
|
redactedEvent.Redact()
|
||||||
err := r.SetUnsignedField("redacted_because", redactionEvent)
|
if err := redactedEvent.SetUnsignedField("redacted_because", redactionEvent); err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
// NOTSPEC: sytest relies on this unspecced field existing :(
|
// NOTSPEC: sytest relies on this unspecced field existing :(
|
||||||
err = r.SetUnsignedField("redacted_by", redactionEvent.EventID())
|
if err := redactedEvent.SetUnsignedField("redacted_by", redactionEvent.EventID()); err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
return r, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,130 +1,142 @@
|
||||||
|
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package sqlutil
|
package sqlutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"sync"
|
||||||
"sort"
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/internal"
|
||||||
"github.com/pressly/goose"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Migrations struct {
|
const createDBMigrationsSQL = "" +
|
||||||
registeredGoMigrations map[int64]*goose.Migration
|
"CREATE TABLE IF NOT EXISTS db_migrations (" +
|
||||||
|
" version TEXT PRIMARY KEY NOT NULL," +
|
||||||
|
" time TEXT NOT NULL," +
|
||||||
|
" dendrite_version TEXT NOT NULL" +
|
||||||
|
");"
|
||||||
|
|
||||||
|
const insertVersionSQL = "" +
|
||||||
|
"INSERT INTO db_migrations (version, time, dendrite_version)" +
|
||||||
|
" VALUES ($1, $2, $3)"
|
||||||
|
|
||||||
|
const selectDBMigrationsSQL = "SELECT version FROM db_migrations"
|
||||||
|
|
||||||
|
// Migration defines a migration to be run.
|
||||||
|
type Migration struct {
|
||||||
|
// Version is a simple description/name of this migration.
|
||||||
|
Version string
|
||||||
|
// Up defines the function to execute for an upgrade.
|
||||||
|
Up func(ctx context.Context, txn *sql.Tx) error
|
||||||
|
// Down defines the function to execute for a downgrade (not implemented yet).
|
||||||
|
Down func(ctx context.Context, txn *sql.Tx) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMigrations() *Migrations {
|
// Migrator
|
||||||
return &Migrations{
|
type Migrator struct {
|
||||||
registeredGoMigrations: make(map[int64]*goose.Migration),
|
db *sql.DB
|
||||||
|
migrations []Migration
|
||||||
|
knownMigrations map[string]struct{}
|
||||||
|
mutex *sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMigrator creates a new DB migrator.
|
||||||
|
func NewMigrator(db *sql.DB) *Migrator {
|
||||||
|
return &Migrator{
|
||||||
|
db: db,
|
||||||
|
migrations: []Migration{},
|
||||||
|
knownMigrations: make(map[string]struct{}),
|
||||||
|
mutex: &sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy-pasted from goose directly to store migrations into a map we control
|
// AddMigrations appends migrations to the list of migrations. Migrations are executed
|
||||||
|
// in the order they are added to the list. De-duplicates migrations using their Version field.
|
||||||
// AddMigration adds a migration.
|
func (m *Migrator) AddMigrations(migrations ...Migration) {
|
||||||
func (m *Migrations) AddMigration(up func(*sql.Tx) error, down func(*sql.Tx) error) {
|
m.mutex.Lock()
|
||||||
_, filename, _, _ := runtime.Caller(1)
|
defer m.mutex.Unlock()
|
||||||
m.AddNamedMigration(filename, up, down)
|
for _, mig := range migrations {
|
||||||
}
|
if _, ok := m.knownMigrations[mig.Version]; !ok {
|
||||||
|
m.migrations = append(m.migrations, mig)
|
||||||
// AddNamedMigration : Add a named migration.
|
m.knownMigrations[mig.Version] = struct{}{}
|
||||||
func (m *Migrations) AddNamedMigration(filename string, up func(*sql.Tx) error, down func(*sql.Tx) error) {
|
}
|
||||||
v, _ := goose.NumericComponent(filename)
|
|
||||||
migration := &goose.Migration{Version: v, Next: -1, Previous: -1, Registered: true, UpFn: up, DownFn: down, Source: filename}
|
|
||||||
|
|
||||||
if existing, ok := m.registeredGoMigrations[v]; ok {
|
|
||||||
panic(fmt.Sprintf("failed to add migration %q: version conflicts with %q", filename, existing.Source))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m.registeredGoMigrations[v] = migration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunDeltas up to the latest version.
|
// Up executes all migrations in order they were added.
|
||||||
func (m *Migrations) RunDeltas(db *sql.DB, props *config.DatabaseOptions) error {
|
func (m *Migrator) Up(ctx context.Context) error {
|
||||||
maxVer := goose.MaxVersion
|
var (
|
||||||
minVer := int64(0)
|
err error
|
||||||
migrations, err := m.collect(minVer, maxVer)
|
dendriteVersion = internal.VersionString()
|
||||||
|
)
|
||||||
|
// ensure there is a table for known migrations
|
||||||
|
executedMigrations, err := m.ExecutedMigrations(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("runDeltas: Failed to collect migrations: %w", err)
|
return fmt.Errorf("unable to create/get migrations: %w", err)
|
||||||
}
|
}
|
||||||
if props.ConnectionString.IsPostgres() {
|
|
||||||
if err = goose.SetDialect("postgres"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if props.ConnectionString.IsSQLite() {
|
|
||||||
if err = goose.SetDialect("sqlite3"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("unknown connection string: %s", props.ConnectionString)
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
current, err := goose.EnsureDBVersion(db)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("runDeltas: Failed to EnsureDBVersion: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
next, err := migrations.Next(current)
|
return WithTransaction(m.db, func(txn *sql.Tx) error {
|
||||||
if err != nil {
|
for i := range m.migrations {
|
||||||
if err == goose.ErrNoNextVersion {
|
now := time.Now().UTC().Format(time.RFC3339)
|
||||||
return nil
|
migration := m.migrations[i]
|
||||||
|
logrus.Debugf("Executing database migration '%s'", migration.Version)
|
||||||
|
// Skip migration if it was already executed
|
||||||
|
if _, ok := executedMigrations[migration.Version]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = migration.Up(ctx, txn)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to execute migration '%s': %w", migration.Version, err)
|
||||||
|
}
|
||||||
|
_, err = txn.ExecContext(ctx, insertVersionSQL,
|
||||||
|
migration.Version,
|
||||||
|
now,
|
||||||
|
dendriteVersion,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to insert executed migrations: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("runDeltas: Failed to load next migration to %+v : %w", next, err)
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
if err = next.Up(db); err != nil {
|
})
|
||||||
return fmt.Errorf("runDeltas: Failed run migration: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Migrations) collect(current, target int64) (goose.Migrations, error) {
|
// ExecutedMigrations returns a map with already executed migrations in addition to creating the
|
||||||
var migrations goose.Migrations
|
// migrations table, if it doesn't exist.
|
||||||
|
func (m *Migrator) ExecutedMigrations(ctx context.Context) (map[string]struct{}, error) {
|
||||||
// Go migrations registered via goose.AddMigration().
|
result := make(map[string]struct{})
|
||||||
for _, migration := range m.registeredGoMigrations {
|
_, err := m.db.ExecContext(ctx, createDBMigrationsSQL)
|
||||||
v, err := goose.NumericComponent(migration.Source)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, fmt.Errorf("unable to create db_migrations: %w", err)
|
||||||
return nil, err
|
}
|
||||||
}
|
rows, err := m.db.QueryContext(ctx, selectDBMigrationsSQL)
|
||||||
if versionFilter(v, current, target) {
|
if err != nil {
|
||||||
migrations = append(migrations, migration)
|
return nil, fmt.Errorf("unable to query db_migrations: %w", err)
|
||||||
|
}
|
||||||
|
defer internal.CloseAndLogIfError(ctx, rows, "ExecutedMigrations: rows.close() failed")
|
||||||
|
var version string
|
||||||
|
for rows.Next() {
|
||||||
|
if err = rows.Scan(&version); err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to scan version: %w", err)
|
||||||
}
|
}
|
||||||
|
result[version] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
migrations = sortAndConnectMigrations(migrations)
|
return result, rows.Err()
|
||||||
|
|
||||||
return migrations, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sortAndConnectMigrations(migrations goose.Migrations) goose.Migrations {
|
|
||||||
sort.Sort(migrations)
|
|
||||||
|
|
||||||
// now that we're sorted in the appropriate direction,
|
|
||||||
// populate next and previous for each migration
|
|
||||||
for i, m := range migrations {
|
|
||||||
prev := int64(-1)
|
|
||||||
if i > 0 {
|
|
||||||
prev = migrations[i-1].Version
|
|
||||||
migrations[i-1].Next = m.Version
|
|
||||||
}
|
|
||||||
migrations[i].Previous = prev
|
|
||||||
}
|
|
||||||
|
|
||||||
return migrations
|
|
||||||
}
|
|
||||||
|
|
||||||
func versionFilter(v, current, target int64) bool {
|
|
||||||
|
|
||||||
if target > current {
|
|
||||||
return v > current && v <= target
|
|
||||||
}
|
|
||||||
|
|
||||||
if target < current {
|
|
||||||
return v <= current && v > target
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
112
internal/sqlutil/migrate_test.go
Normal file
112
internal/sqlutil/migrate_test.go
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
package sqlutil_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/test"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dummyMigrations = []sqlutil.Migration{
|
||||||
|
{
|
||||||
|
Version: "init",
|
||||||
|
Up: func(ctx context.Context, txn *sql.Tx) error {
|
||||||
|
_, err := txn.ExecContext(ctx, "CREATE TABLE IF NOT EXISTS dummy ( test TEXT );")
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "v2",
|
||||||
|
Up: func(ctx context.Context, txn *sql.Tx) error {
|
||||||
|
_, err := txn.ExecContext(ctx, "ALTER TABLE dummy ADD COLUMN test2 TEXT;")
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "v2", // duplicate, this migration will be skipped
|
||||||
|
Up: func(ctx context.Context, txn *sql.Tx) error {
|
||||||
|
_, err := txn.ExecContext(ctx, "ALTER TABLE dummy ADD COLUMN test2 TEXT;")
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Version: "multiple execs",
|
||||||
|
Up: func(ctx context.Context, txn *sql.Tx) error {
|
||||||
|
_, err := txn.ExecContext(ctx, "ALTER TABLE dummy ADD COLUMN test3 TEXT;")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = txn.ExecContext(ctx, "ALTER TABLE dummy ADD COLUMN test4 TEXT;")
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var failMigration = sqlutil.Migration{
|
||||||
|
Version: "iFail",
|
||||||
|
Up: func(ctx context.Context, txn *sql.Tx) error {
|
||||||
|
return fmt.Errorf("iFail")
|
||||||
|
},
|
||||||
|
Down: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_migrations_Up(t *testing.T) {
|
||||||
|
withFail := append(dummyMigrations, failMigration)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
migrations []sqlutil.Migration
|
||||||
|
wantResult map[string]struct{}
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "dummy migration",
|
||||||
|
migrations: dummyMigrations,
|
||||||
|
wantResult: map[string]struct{}{
|
||||||
|
"init": {},
|
||||||
|
"v2": {},
|
||||||
|
"multiple execs": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "with fail",
|
||||||
|
migrations: withFail,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
|
conStr, close := test.PrepareDBConnectionString(t, dbType)
|
||||||
|
defer close()
|
||||||
|
driverName := "sqlite3"
|
||||||
|
if dbType == test.DBTypePostgres {
|
||||||
|
driverName = "postgres"
|
||||||
|
}
|
||||||
|
db, err := sql.Open(driverName, conStr)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to open database: %v", err)
|
||||||
|
}
|
||||||
|
m := sqlutil.NewMigrator(db)
|
||||||
|
m.AddMigrations(tt.migrations...)
|
||||||
|
if err = m.Up(ctx); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Up() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
result, err := m.ExecutedMigrations(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to get executed migrations: %v", err)
|
||||||
|
}
|
||||||
|
if !tt.wantErr && !reflect.DeepEqual(result, tt.wantResult) {
|
||||||
|
t.Errorf("expected: %+v, got %v", tt.wantResult, result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,8 +16,8 @@ var build string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
VersionMajor = 0
|
VersionMajor = 0
|
||||||
VersionMinor = 8
|
VersionMinor = 9
|
||||||
VersionPatch = 9
|
VersionPatch = 0
|
||||||
VersionTag = "" // example: "rc1"
|
VersionTag = "" // example: "rc1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal"
|
"github.com/matrix-org/dendrite/internal"
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/keyserver/storage/postgres/deltas"
|
||||||
"github.com/matrix-org/dendrite/keyserver/storage/tables"
|
"github.com/matrix-org/dendrite/keyserver/storage/tables"
|
||||||
"github.com/matrix-org/dendrite/keyserver/types"
|
"github.com/matrix-org/dendrite/keyserver/types"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
@ -66,6 +67,16 @@ func NewPostgresCrossSigningSigsTable(db *sql.DB) (tables.CrossSigningSigs, erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m := sqlutil.NewMigrator(db)
|
||||||
|
m.AddMigrations(sqlutil.Migration{
|
||||||
|
Version: "keyserver: cross signing signature indexes",
|
||||||
|
Up: deltas.UpFixCrossSigningSignatureIndexes,
|
||||||
|
})
|
||||||
|
if err = m.Up(context.Background()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return s, sqlutil.StatementList{
|
return s, sqlutil.StatementList{
|
||||||
{&s.selectCrossSigningSigsForTargetStmt, selectCrossSigningSigsForTargetSQL},
|
{&s.selectCrossSigningSigsForTargetStmt, selectCrossSigningSigsForTargetSQL},
|
||||||
{&s.upsertCrossSigningSigsForTargetStmt, upsertCrossSigningSigsForTargetSQL},
|
{&s.upsertCrossSigningSigsForTargetStmt, upsertCrossSigningSigsForTargetSQL},
|
||||||
|
|
|
||||||
|
|
@ -15,37 +15,27 @@
|
||||||
package deltas
|
package deltas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
|
||||||
"github.com/pressly/goose"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadFromGoose() {
|
func UpRefactorKeyChanges(ctx context.Context, tx *sql.Tx) error {
|
||||||
goose.AddMigration(UpRefactorKeyChanges, DownRefactorKeyChanges)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadRefactorKeyChanges(m *sqlutil.Migrations) {
|
|
||||||
m.AddMigration(UpRefactorKeyChanges, DownRefactorKeyChanges)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpRefactorKeyChanges(tx *sql.Tx) error {
|
|
||||||
// start counting from the last max offset, else 0. We need to do a count(*) first to see if there
|
// start counting from the last max offset, else 0. We need to do a count(*) first to see if there
|
||||||
// even are entries in this table to know if we can query for log_offset. Without the count then
|
// even are entries in this table to know if we can query for log_offset. Without the count then
|
||||||
// the query to SELECT the max log offset fails on new Dendrite instances as log_offset doesn't
|
// the query to SELECT the max log offset fails on new Dendrite instances as log_offset doesn't
|
||||||
// exist on that table. Even though we discard the error, the txn is tainted and gets aborted :/
|
// exist on that table. Even though we discard the error, the txn is tainted and gets aborted :/
|
||||||
var count int
|
var count int
|
||||||
_ = tx.QueryRow(`SELECT count(*) FROM keyserver_key_changes`).Scan(&count)
|
_ = tx.QueryRowContext(ctx, `SELECT count(*) FROM keyserver_key_changes`).Scan(&count)
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
var maxOffset int64
|
var maxOffset int64
|
||||||
_ = tx.QueryRow(`SELECT coalesce(MAX(log_offset), 0) AS offset FROM keyserver_key_changes`).Scan(&maxOffset)
|
_ = tx.QueryRowContext(ctx, `SELECT coalesce(MAX(log_offset), 0) AS offset FROM keyserver_key_changes`).Scan(&maxOffset)
|
||||||
if _, err := tx.Exec(fmt.Sprintf(`CREATE SEQUENCE IF NOT EXISTS keyserver_key_changes_seq START %d`, maxOffset)); err != nil {
|
if _, err := tx.ExecContext(ctx, fmt.Sprintf(`CREATE SEQUENCE IF NOT EXISTS keyserver_key_changes_seq START %d`, maxOffset)); err != nil {
|
||||||
return fmt.Errorf("failed to CREATE SEQUENCE for key changes, starting at %d: %s", maxOffset, err)
|
return fmt.Errorf("failed to CREATE SEQUENCE for key changes, starting at %d: %s", maxOffset, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := tx.Exec(`
|
_, err := tx.ExecContext(ctx, `
|
||||||
-- make the new table
|
-- make the new table
|
||||||
DROP TABLE IF EXISTS keyserver_key_changes;
|
DROP TABLE IF EXISTS keyserver_key_changes;
|
||||||
CREATE TABLE IF NOT EXISTS keyserver_key_changes (
|
CREATE TABLE IF NOT EXISTS keyserver_key_changes (
|
||||||
|
|
@ -60,8 +50,8 @@ func UpRefactorKeyChanges(tx *sql.Tx) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DownRefactorKeyChanges(tx *sql.Tx) error {
|
func DownRefactorKeyChanges(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.Exec(`
|
_, err := tx.ExecContext(ctx, `
|
||||||
-- Drop all data and revert back, we can't keep the data as Kafka offsets determine the numbers
|
-- Drop all data and revert back, we can't keep the data as Kafka offsets determine the numbers
|
||||||
DROP SEQUENCE IF EXISTS keyserver_key_changes_seq;
|
DROP SEQUENCE IF EXISTS keyserver_key_changes_seq;
|
||||||
DROP TABLE IF EXISTS keyserver_key_changes;
|
DROP TABLE IF EXISTS keyserver_key_changes;
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,13 @@
|
||||||
package deltas
|
package deltas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadFixCrossSigningSignatureIndexes(m *sqlutil.Migrations) {
|
func UpFixCrossSigningSignatureIndexes(ctx context.Context, tx *sql.Tx) error {
|
||||||
m.AddMigration(UpFixCrossSigningSignatureIndexes, DownFixCrossSigningSignatureIndexes)
|
_, err := tx.ExecContext(ctx, `
|
||||||
}
|
|
||||||
|
|
||||||
func UpFixCrossSigningSignatureIndexes(tx *sql.Tx) error {
|
|
||||||
_, err := tx.Exec(`
|
|
||||||
ALTER TABLE keyserver_cross_signing_sigs DROP CONSTRAINT keyserver_cross_signing_sigs_pkey;
|
ALTER TABLE keyserver_cross_signing_sigs DROP CONSTRAINT keyserver_cross_signing_sigs_pkey;
|
||||||
ALTER TABLE keyserver_cross_signing_sigs ADD PRIMARY KEY (origin_user_id, origin_key_id, target_user_id, target_key_id);
|
ALTER TABLE keyserver_cross_signing_sigs ADD PRIMARY KEY (origin_user_id, origin_key_id, target_user_id, target_key_id);
|
||||||
|
|
||||||
|
|
@ -38,8 +33,8 @@ func UpFixCrossSigningSignatureIndexes(tx *sql.Tx) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DownFixCrossSigningSignatureIndexes(tx *sql.Tx) error {
|
func DownFixCrossSigningSignatureIndexes(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.Exec(`
|
_, err := tx.ExecContext(ctx, `
|
||||||
ALTER TABLE keyserver_cross_signing_sigs DROP CONSTRAINT keyserver_cross_signing_sigs_pkey;
|
ALTER TABLE keyserver_cross_signing_sigs DROP CONSTRAINT keyserver_cross_signing_sigs_pkey;
|
||||||
ALTER TABLE keyserver_cross_signing_sigs ADD PRIMARY KEY (origin_user_id, target_user_id, target_key_id);
|
ALTER TABLE keyserver_cross_signing_sigs ADD PRIMARY KEY (origin_user_id, target_user_id, target_key_id);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal"
|
"github.com/matrix-org/dendrite/internal"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/keyserver/storage/postgres/deltas"
|
||||||
"github.com/matrix-org/dendrite/keyserver/storage/tables"
|
"github.com/matrix-org/dendrite/keyserver/storage/tables"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -55,7 +57,23 @@ func NewPostgresKeyChangesTable(db *sql.DB) (tables.KeyChanges, error) {
|
||||||
db: db,
|
db: db,
|
||||||
}
|
}
|
||||||
_, err := db.Exec(keyChangesSchema)
|
_, err := db.Exec(keyChangesSchema)
|
||||||
return s, err
|
if err != nil {
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove when we are sure we are not having goose artefacts in the db
|
||||||
|
// This forces an error, which indicates the migration is already applied, since the
|
||||||
|
// column partition was removed from the table
|
||||||
|
err = db.QueryRow("SELECT partition FROM keyserver_key_changes LIMIT 1;").Scan()
|
||||||
|
if err == nil {
|
||||||
|
m := sqlutil.NewMigrator(db)
|
||||||
|
m.AddMigrations(sqlutil.Migration{
|
||||||
|
Version: "keyserver: refactor key changes",
|
||||||
|
Up: deltas.UpRefactorKeyChanges,
|
||||||
|
})
|
||||||
|
return s, m.Up(context.Background())
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *keyChangesStatements) Prepare() (err error) {
|
func (s *keyChangesStatements) Prepare() (err error) {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ package postgres
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/dendrite/keyserver/storage/postgres/deltas"
|
|
||||||
"github.com/matrix-org/dendrite/keyserver/storage/shared"
|
"github.com/matrix-org/dendrite/keyserver/storage/shared"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
"github.com/matrix-org/dendrite/setup/base"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
|
|
@ -53,12 +52,6 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
m := sqlutil.NewMigrations()
|
|
||||||
deltas.LoadRefactorKeyChanges(m)
|
|
||||||
deltas.LoadFixCrossSigningSignatureIndexes(m)
|
|
||||||
if err = m.RunDeltas(db, dbProperties); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err = kc.Prepare(); err != nil {
|
if err = kc.Prepare(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal"
|
"github.com/matrix-org/dendrite/internal"
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/keyserver/storage/sqlite3/deltas"
|
||||||
"github.com/matrix-org/dendrite/keyserver/storage/tables"
|
"github.com/matrix-org/dendrite/keyserver/storage/tables"
|
||||||
"github.com/matrix-org/dendrite/keyserver/types"
|
"github.com/matrix-org/dendrite/keyserver/types"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
@ -65,6 +66,15 @@ func NewSqliteCrossSigningSigsTable(db *sql.DB) (tables.CrossSigningSigs, error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
m := sqlutil.NewMigrator(db)
|
||||||
|
m.AddMigrations(sqlutil.Migration{
|
||||||
|
Version: "keyserver: cross signing signature indexes",
|
||||||
|
Up: deltas.UpFixCrossSigningSignatureIndexes,
|
||||||
|
})
|
||||||
|
if err = m.Up(context.Background()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return s, sqlutil.StatementList{
|
return s, sqlutil.StatementList{
|
||||||
{&s.selectCrossSigningSigsForTargetStmt, selectCrossSigningSigsForTargetSQL},
|
{&s.selectCrossSigningSigsForTargetStmt, selectCrossSigningSigsForTargetSQL},
|
||||||
{&s.upsertCrossSigningSigsForTargetStmt, upsertCrossSigningSigsForTargetSQL},
|
{&s.upsertCrossSigningSigsForTargetStmt, upsertCrossSigningSigsForTargetSQL},
|
||||||
|
|
|
||||||
|
|
@ -15,28 +15,18 @@
|
||||||
package deltas
|
package deltas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
|
||||||
"github.com/pressly/goose"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadFromGoose() {
|
func UpRefactorKeyChanges(ctx context.Context, tx *sql.Tx) error {
|
||||||
goose.AddMigration(UpRefactorKeyChanges, DownRefactorKeyChanges)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadRefactorKeyChanges(m *sqlutil.Migrations) {
|
|
||||||
m.AddMigration(UpRefactorKeyChanges, DownRefactorKeyChanges)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpRefactorKeyChanges(tx *sql.Tx) error {
|
|
||||||
// start counting from the last max offset, else 0.
|
// start counting from the last max offset, else 0.
|
||||||
var maxOffset int64
|
var maxOffset int64
|
||||||
var userID string
|
var userID string
|
||||||
_ = tx.QueryRow(`SELECT user_id, MAX(log_offset) FROM keyserver_key_changes GROUP BY user_id`).Scan(&userID, &maxOffset)
|
_ = tx.QueryRowContext(ctx, `SELECT user_id, MAX(log_offset) FROM keyserver_key_changes GROUP BY user_id`).Scan(&userID, &maxOffset)
|
||||||
|
|
||||||
_, err := tx.Exec(`
|
_, err := tx.ExecContext(ctx, `
|
||||||
-- make the new table
|
-- make the new table
|
||||||
DROP TABLE IF EXISTS keyserver_key_changes;
|
DROP TABLE IF EXISTS keyserver_key_changes;
|
||||||
CREATE TABLE IF NOT EXISTS keyserver_key_changes (
|
CREATE TABLE IF NOT EXISTS keyserver_key_changes (
|
||||||
|
|
@ -51,14 +41,14 @@ func UpRefactorKeyChanges(tx *sql.Tx) error {
|
||||||
}
|
}
|
||||||
// to start counting from maxOffset, insert a row with that value
|
// to start counting from maxOffset, insert a row with that value
|
||||||
if userID != "" {
|
if userID != "" {
|
||||||
_, err = tx.Exec(`INSERT INTO keyserver_key_changes(change_id, user_id) VALUES($1, $2)`, maxOffset, userID)
|
_, err = tx.ExecContext(ctx, `INSERT INTO keyserver_key_changes(change_id, user_id) VALUES($1, $2)`, maxOffset, userID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DownRefactorKeyChanges(tx *sql.Tx) error {
|
func DownRefactorKeyChanges(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.Exec(`
|
_, err := tx.ExecContext(ctx, `
|
||||||
-- Drop all data and revert back, we can't keep the data as Kafka offsets determine the numbers
|
-- Drop all data and revert back, we can't keep the data as Kafka offsets determine the numbers
|
||||||
DROP TABLE IF EXISTS keyserver_key_changes;
|
DROP TABLE IF EXISTS keyserver_key_changes;
|
||||||
CREATE TABLE IF NOT EXISTS keyserver_key_changes (
|
CREATE TABLE IF NOT EXISTS keyserver_key_changes (
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,13 @@
|
||||||
package deltas
|
package deltas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadFixCrossSigningSignatureIndexes(m *sqlutil.Migrations) {
|
func UpFixCrossSigningSignatureIndexes(ctx context.Context, tx *sql.Tx) error {
|
||||||
m.AddMigration(UpFixCrossSigningSignatureIndexes, DownFixCrossSigningSignatureIndexes)
|
_, err := tx.ExecContext(ctx, `
|
||||||
}
|
|
||||||
|
|
||||||
func UpFixCrossSigningSignatureIndexes(tx *sql.Tx) error {
|
|
||||||
_, err := tx.Exec(`
|
|
||||||
CREATE TABLE IF NOT EXISTS keyserver_cross_signing_sigs_tmp (
|
CREATE TABLE IF NOT EXISTS keyserver_cross_signing_sigs_tmp (
|
||||||
origin_user_id TEXT NOT NULL,
|
origin_user_id TEXT NOT NULL,
|
||||||
origin_key_id TEXT NOT NULL,
|
origin_key_id TEXT NOT NULL,
|
||||||
|
|
@ -50,8 +45,8 @@ func UpFixCrossSigningSignatureIndexes(tx *sql.Tx) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DownFixCrossSigningSignatureIndexes(tx *sql.Tx) error {
|
func DownFixCrossSigningSignatureIndexes(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.Exec(`
|
_, err := tx.ExecContext(ctx, `
|
||||||
CREATE TABLE IF NOT EXISTS keyserver_cross_signing_sigs_tmp (
|
CREATE TABLE IF NOT EXISTS keyserver_cross_signing_sigs_tmp (
|
||||||
origin_user_id TEXT NOT NULL,
|
origin_user_id TEXT NOT NULL,
|
||||||
origin_key_id TEXT NOT NULL,
|
origin_key_id TEXT NOT NULL,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal"
|
"github.com/matrix-org/dendrite/internal"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/keyserver/storage/sqlite3/deltas"
|
||||||
"github.com/matrix-org/dendrite/keyserver/storage/tables"
|
"github.com/matrix-org/dendrite/keyserver/storage/tables"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -53,7 +55,23 @@ func NewSqliteKeyChangesTable(db *sql.DB) (tables.KeyChanges, error) {
|
||||||
db: db,
|
db: db,
|
||||||
}
|
}
|
||||||
_, err := db.Exec(keyChangesSchema)
|
_, err := db.Exec(keyChangesSchema)
|
||||||
return s, err
|
if err != nil {
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
// TODO: Remove when we are sure we are not having goose artefacts in the db
|
||||||
|
// This forces an error, which indicates the migration is already applied, since the
|
||||||
|
// column partition was removed from the table
|
||||||
|
err = db.QueryRow("SELECT partition FROM keyserver_key_changes LIMIT 1;").Scan()
|
||||||
|
if err == nil {
|
||||||
|
m := sqlutil.NewMigrator(db)
|
||||||
|
m.AddMigrations(sqlutil.Migration{
|
||||||
|
Version: "keyserver: refactor key changes",
|
||||||
|
Up: deltas.UpRefactorKeyChanges,
|
||||||
|
})
|
||||||
|
return s, m.Up(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *keyChangesStatements) Prepare() (err error) {
|
func (s *keyChangesStatements) Prepare() (err error) {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ package sqlite3
|
||||||
import (
|
import (
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/dendrite/keyserver/storage/shared"
|
"github.com/matrix-org/dendrite/keyserver/storage/shared"
|
||||||
"github.com/matrix-org/dendrite/keyserver/storage/sqlite3/deltas"
|
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
"github.com/matrix-org/dendrite/setup/base"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
)
|
)
|
||||||
|
|
@ -52,12 +51,6 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
m := sqlutil.NewMigrations()
|
|
||||||
deltas.LoadRefactorKeyChanges(m)
|
|
||||||
deltas.LoadFixCrossSigningSignatureIndexes(m)
|
|
||||||
if err = m.RunDeltas(db, dbProperties); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err = kc.Prepare(); err != nil {
|
if err = kc.Prepare(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,26 @@
|
||||||
package storage
|
package storage_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/keyserver/api"
|
"github.com/matrix-org/dendrite/keyserver/api"
|
||||||
|
"github.com/matrix-org/dendrite/keyserver/storage"
|
||||||
"github.com/matrix-org/dendrite/keyserver/types"
|
"github.com/matrix-org/dendrite/keyserver/types"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/test"
|
||||||
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ctx = context.Background()
|
var ctx = context.Background()
|
||||||
|
|
||||||
func MustCreateDatabase(t *testing.T) (Database, func()) {
|
func MustCreateDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) {
|
||||||
tmpfile, err := ioutil.TempFile("", "keyserver_storage_test")
|
base, close := testrig.CreateBaseDendrite(t, dbType)
|
||||||
|
db, err := storage.NewDatabase(base, &base.Cfg.KeyServer.Database)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
t.Fatalf("failed to create new database: %v", err)
|
||||||
}
|
|
||||||
t.Logf("Database %s", tmpfile.Name())
|
|
||||||
db, err := NewDatabase(nil, &config.DatabaseOptions{
|
|
||||||
ConnectionString: config.DataSource(fmt.Sprintf("file://%s", tmpfile.Name())),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to NewDatabase: %s", err)
|
|
||||||
}
|
|
||||||
return db, func() {
|
|
||||||
os.Remove(tmpfile.Name())
|
|
||||||
}
|
}
|
||||||
|
return db, close
|
||||||
}
|
}
|
||||||
|
|
||||||
func MustNotError(t *testing.T, err error) {
|
func MustNotError(t *testing.T, err error) {
|
||||||
|
|
@ -42,151 +32,159 @@ func MustNotError(t *testing.T, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyChanges(t *testing.T) {
|
func TestKeyChanges(t *testing.T) {
|
||||||
db, clean := MustCreateDatabase(t)
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
defer clean()
|
db, clean := MustCreateDatabase(t, dbType)
|
||||||
_, err := db.StoreKeyChange(ctx, "@alice:localhost")
|
defer clean()
|
||||||
MustNotError(t, err)
|
_, err := db.StoreKeyChange(ctx, "@alice:localhost")
|
||||||
deviceChangeIDB, err := db.StoreKeyChange(ctx, "@bob:localhost")
|
MustNotError(t, err)
|
||||||
MustNotError(t, err)
|
deviceChangeIDB, err := db.StoreKeyChange(ctx, "@bob:localhost")
|
||||||
deviceChangeIDC, err := db.StoreKeyChange(ctx, "@charlie:localhost")
|
MustNotError(t, err)
|
||||||
MustNotError(t, err)
|
deviceChangeIDC, err := db.StoreKeyChange(ctx, "@charlie:localhost")
|
||||||
userIDs, latest, err := db.KeyChanges(ctx, deviceChangeIDB, types.OffsetNewest)
|
MustNotError(t, err)
|
||||||
if err != nil {
|
userIDs, latest, err := db.KeyChanges(ctx, deviceChangeIDB, types.OffsetNewest)
|
||||||
t.Fatalf("Failed to KeyChanges: %s", err)
|
if err != nil {
|
||||||
}
|
t.Fatalf("Failed to KeyChanges: %s", err)
|
||||||
if latest != deviceChangeIDC {
|
}
|
||||||
t.Fatalf("KeyChanges: got latest=%d want %d", latest, deviceChangeIDC)
|
if latest != deviceChangeIDC {
|
||||||
}
|
t.Fatalf("KeyChanges: got latest=%d want %d", latest, deviceChangeIDC)
|
||||||
if !reflect.DeepEqual(userIDs, []string{"@charlie:localhost"}) {
|
}
|
||||||
t.Fatalf("KeyChanges: wrong user_ids: %v", userIDs)
|
if !reflect.DeepEqual(userIDs, []string{"@charlie:localhost"}) {
|
||||||
}
|
t.Fatalf("KeyChanges: wrong user_ids: %v", userIDs)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyChangesNoDupes(t *testing.T) {
|
func TestKeyChangesNoDupes(t *testing.T) {
|
||||||
db, clean := MustCreateDatabase(t)
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
defer clean()
|
db, clean := MustCreateDatabase(t, dbType)
|
||||||
deviceChangeIDA, err := db.StoreKeyChange(ctx, "@alice:localhost")
|
defer clean()
|
||||||
MustNotError(t, err)
|
deviceChangeIDA, err := db.StoreKeyChange(ctx, "@alice:localhost")
|
||||||
deviceChangeIDB, err := db.StoreKeyChange(ctx, "@alice:localhost")
|
MustNotError(t, err)
|
||||||
MustNotError(t, err)
|
deviceChangeIDB, err := db.StoreKeyChange(ctx, "@alice:localhost")
|
||||||
if deviceChangeIDA == deviceChangeIDB {
|
MustNotError(t, err)
|
||||||
t.Fatalf("Expected change ID to be different even when inserting key change for the same user, got %d for both changes", deviceChangeIDA)
|
if deviceChangeIDA == deviceChangeIDB {
|
||||||
}
|
t.Fatalf("Expected change ID to be different even when inserting key change for the same user, got %d for both changes", deviceChangeIDA)
|
||||||
deviceChangeID, err := db.StoreKeyChange(ctx, "@alice:localhost")
|
}
|
||||||
MustNotError(t, err)
|
deviceChangeID, err := db.StoreKeyChange(ctx, "@alice:localhost")
|
||||||
userIDs, latest, err := db.KeyChanges(ctx, 0, types.OffsetNewest)
|
MustNotError(t, err)
|
||||||
if err != nil {
|
userIDs, latest, err := db.KeyChanges(ctx, 0, types.OffsetNewest)
|
||||||
t.Fatalf("Failed to KeyChanges: %s", err)
|
if err != nil {
|
||||||
}
|
t.Fatalf("Failed to KeyChanges: %s", err)
|
||||||
if latest != deviceChangeID {
|
}
|
||||||
t.Fatalf("KeyChanges: got latest=%d want %d", latest, deviceChangeID)
|
if latest != deviceChangeID {
|
||||||
}
|
t.Fatalf("KeyChanges: got latest=%d want %d", latest, deviceChangeID)
|
||||||
if !reflect.DeepEqual(userIDs, []string{"@alice:localhost"}) {
|
}
|
||||||
t.Fatalf("KeyChanges: wrong user_ids: %v", userIDs)
|
if !reflect.DeepEqual(userIDs, []string{"@alice:localhost"}) {
|
||||||
}
|
t.Fatalf("KeyChanges: wrong user_ids: %v", userIDs)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyChangesUpperLimit(t *testing.T) {
|
func TestKeyChangesUpperLimit(t *testing.T) {
|
||||||
db, clean := MustCreateDatabase(t)
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
defer clean()
|
db, clean := MustCreateDatabase(t, dbType)
|
||||||
deviceChangeIDA, err := db.StoreKeyChange(ctx, "@alice:localhost")
|
defer clean()
|
||||||
MustNotError(t, err)
|
deviceChangeIDA, err := db.StoreKeyChange(ctx, "@alice:localhost")
|
||||||
deviceChangeIDB, err := db.StoreKeyChange(ctx, "@bob:localhost")
|
MustNotError(t, err)
|
||||||
MustNotError(t, err)
|
deviceChangeIDB, err := db.StoreKeyChange(ctx, "@bob:localhost")
|
||||||
_, err = db.StoreKeyChange(ctx, "@charlie:localhost")
|
MustNotError(t, err)
|
||||||
MustNotError(t, err)
|
_, err = db.StoreKeyChange(ctx, "@charlie:localhost")
|
||||||
userIDs, latest, err := db.KeyChanges(ctx, deviceChangeIDA, deviceChangeIDB)
|
MustNotError(t, err)
|
||||||
if err != nil {
|
userIDs, latest, err := db.KeyChanges(ctx, deviceChangeIDA, deviceChangeIDB)
|
||||||
t.Fatalf("Failed to KeyChanges: %s", err)
|
if err != nil {
|
||||||
}
|
t.Fatalf("Failed to KeyChanges: %s", err)
|
||||||
if latest != deviceChangeIDB {
|
}
|
||||||
t.Fatalf("KeyChanges: got latest=%d want %d", latest, deviceChangeIDB)
|
if latest != deviceChangeIDB {
|
||||||
}
|
t.Fatalf("KeyChanges: got latest=%d want %d", latest, deviceChangeIDB)
|
||||||
if !reflect.DeepEqual(userIDs, []string{"@bob:localhost"}) {
|
}
|
||||||
t.Fatalf("KeyChanges: wrong user_ids: %v", userIDs)
|
if !reflect.DeepEqual(userIDs, []string{"@bob:localhost"}) {
|
||||||
}
|
t.Fatalf("KeyChanges: wrong user_ids: %v", userIDs)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// The purpose of this test is to make sure that the storage layer is generating sequential stream IDs per user,
|
// The purpose of this test is to make sure that the storage layer is generating sequential stream IDs per user,
|
||||||
// and that they are returned correctly when querying for device keys.
|
// and that they are returned correctly when querying for device keys.
|
||||||
func TestDeviceKeysStreamIDGeneration(t *testing.T) {
|
func TestDeviceKeysStreamIDGeneration(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
db, clean := MustCreateDatabase(t)
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
defer clean()
|
db, clean := MustCreateDatabase(t, dbType)
|
||||||
alice := "@alice:TestDeviceKeysStreamIDGeneration"
|
defer clean()
|
||||||
bob := "@bob:TestDeviceKeysStreamIDGeneration"
|
alice := "@alice:TestDeviceKeysStreamIDGeneration"
|
||||||
msgs := []api.DeviceMessage{
|
bob := "@bob:TestDeviceKeysStreamIDGeneration"
|
||||||
{
|
msgs := []api.DeviceMessage{
|
||||||
Type: api.TypeDeviceKeyUpdate,
|
{
|
||||||
DeviceKeys: &api.DeviceKeys{
|
Type: api.TypeDeviceKeyUpdate,
|
||||||
DeviceID: "AAA",
|
DeviceKeys: &api.DeviceKeys{
|
||||||
UserID: alice,
|
DeviceID: "AAA",
|
||||||
KeyJSON: []byte(`{"key":"v1"}`),
|
UserID: alice,
|
||||||
|
KeyJSON: []byte(`{"key":"v1"}`),
|
||||||
|
},
|
||||||
|
// StreamID: 1
|
||||||
},
|
},
|
||||||
// StreamID: 1
|
{
|
||||||
},
|
Type: api.TypeDeviceKeyUpdate,
|
||||||
{
|
DeviceKeys: &api.DeviceKeys{
|
||||||
Type: api.TypeDeviceKeyUpdate,
|
DeviceID: "AAA",
|
||||||
DeviceKeys: &api.DeviceKeys{
|
UserID: bob,
|
||||||
DeviceID: "AAA",
|
KeyJSON: []byte(`{"key":"v1"}`),
|
||||||
UserID: bob,
|
},
|
||||||
KeyJSON: []byte(`{"key":"v1"}`),
|
// StreamID: 1 as this is a different user
|
||||||
},
|
},
|
||||||
// StreamID: 1 as this is a different user
|
{
|
||||||
},
|
Type: api.TypeDeviceKeyUpdate,
|
||||||
{
|
DeviceKeys: &api.DeviceKeys{
|
||||||
Type: api.TypeDeviceKeyUpdate,
|
DeviceID: "another_device",
|
||||||
DeviceKeys: &api.DeviceKeys{
|
UserID: alice,
|
||||||
DeviceID: "another_device",
|
KeyJSON: []byte(`{"key":"v1"}`),
|
||||||
UserID: alice,
|
},
|
||||||
KeyJSON: []byte(`{"key":"v1"}`),
|
// StreamID: 2 as this is a 2nd device key
|
||||||
},
|
},
|
||||||
// StreamID: 2 as this is a 2nd device key
|
|
||||||
},
|
|
||||||
}
|
|
||||||
MustNotError(t, db.StoreLocalDeviceKeys(ctx, msgs))
|
|
||||||
if msgs[0].StreamID != 1 {
|
|
||||||
t.Fatalf("Expected StoreLocalDeviceKeys to set StreamID=1 but got %d", msgs[0].StreamID)
|
|
||||||
}
|
|
||||||
if msgs[1].StreamID != 1 {
|
|
||||||
t.Fatalf("Expected StoreLocalDeviceKeys to set StreamID=1 (different user) but got %d", msgs[1].StreamID)
|
|
||||||
}
|
|
||||||
if msgs[2].StreamID != 2 {
|
|
||||||
t.Fatalf("Expected StoreLocalDeviceKeys to set StreamID=2 (another device) but got %d", msgs[2].StreamID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// updating a device sets the next stream ID for that user
|
|
||||||
msgs = []api.DeviceMessage{
|
|
||||||
{
|
|
||||||
Type: api.TypeDeviceKeyUpdate,
|
|
||||||
DeviceKeys: &api.DeviceKeys{
|
|
||||||
DeviceID: "AAA",
|
|
||||||
UserID: alice,
|
|
||||||
KeyJSON: []byte(`{"key":"v2"}`),
|
|
||||||
},
|
|
||||||
// StreamID: 3
|
|
||||||
},
|
|
||||||
}
|
|
||||||
MustNotError(t, db.StoreLocalDeviceKeys(ctx, msgs))
|
|
||||||
if msgs[0].StreamID != 3 {
|
|
||||||
t.Fatalf("Expected StoreLocalDeviceKeys to set StreamID=3 (new key same device) but got %d", msgs[0].StreamID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Querying for device keys returns the latest stream IDs
|
|
||||||
msgs, err = db.DeviceKeysForUser(ctx, alice, []string{"AAA", "another_device"}, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("DeviceKeysForUser returned error: %s", err)
|
|
||||||
}
|
|
||||||
wantStreamIDs := map[string]int64{
|
|
||||||
"AAA": 3,
|
|
||||||
"another_device": 2,
|
|
||||||
}
|
|
||||||
if len(msgs) != len(wantStreamIDs) {
|
|
||||||
t.Fatalf("DeviceKeysForUser: wrong number of devices, got %d want %d", len(msgs), len(wantStreamIDs))
|
|
||||||
}
|
|
||||||
for _, m := range msgs {
|
|
||||||
if m.StreamID != wantStreamIDs[m.DeviceID] {
|
|
||||||
t.Errorf("DeviceKeysForUser: wrong returned stream ID for key, got %d want %d", m.StreamID, wantStreamIDs[m.DeviceID])
|
|
||||||
}
|
}
|
||||||
}
|
MustNotError(t, db.StoreLocalDeviceKeys(ctx, msgs))
|
||||||
|
if msgs[0].StreamID != 1 {
|
||||||
|
t.Fatalf("Expected StoreLocalDeviceKeys to set StreamID=1 but got %d", msgs[0].StreamID)
|
||||||
|
}
|
||||||
|
if msgs[1].StreamID != 1 {
|
||||||
|
t.Fatalf("Expected StoreLocalDeviceKeys to set StreamID=1 (different user) but got %d", msgs[1].StreamID)
|
||||||
|
}
|
||||||
|
if msgs[2].StreamID != 2 {
|
||||||
|
t.Fatalf("Expected StoreLocalDeviceKeys to set StreamID=2 (another device) but got %d", msgs[2].StreamID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// updating a device sets the next stream ID for that user
|
||||||
|
msgs = []api.DeviceMessage{
|
||||||
|
{
|
||||||
|
Type: api.TypeDeviceKeyUpdate,
|
||||||
|
DeviceKeys: &api.DeviceKeys{
|
||||||
|
DeviceID: "AAA",
|
||||||
|
UserID: alice,
|
||||||
|
KeyJSON: []byte(`{"key":"v2"}`),
|
||||||
|
},
|
||||||
|
// StreamID: 3
|
||||||
|
},
|
||||||
|
}
|
||||||
|
MustNotError(t, db.StoreLocalDeviceKeys(ctx, msgs))
|
||||||
|
if msgs[0].StreamID != 3 {
|
||||||
|
t.Fatalf("Expected StoreLocalDeviceKeys to set StreamID=3 (new key same device) but got %d", msgs[0].StreamID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Querying for device keys returns the latest stream IDs
|
||||||
|
msgs, err = db.DeviceKeysForUser(ctx, alice, []string{"AAA", "another_device"}, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("DeviceKeysForUser returned error: %s", err)
|
||||||
|
}
|
||||||
|
wantStreamIDs := map[string]int64{
|
||||||
|
"AAA": 3,
|
||||||
|
"another_device": 2,
|
||||||
|
}
|
||||||
|
if len(msgs) != len(wantStreamIDs) {
|
||||||
|
t.Fatalf("DeviceKeysForUser: wrong number of devices, got %d want %d", len(msgs), len(wantStreamIDs))
|
||||||
|
}
|
||||||
|
for _, m := range msgs {
|
||||||
|
if m.StreamID != wantStreamIDs[m.DeviceID] {
|
||||||
|
t.Errorf("DeviceKeysForUser: wrong returned stream ID for key, got %d want %d", m.StreamID, wantStreamIDs[m.DeviceID])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/roomserver/internal/query"
|
"github.com/matrix-org/dendrite/roomserver/internal/query"
|
||||||
"github.com/matrix-org/dendrite/roomserver/producers"
|
"github.com/matrix-org/dendrite/roomserver/producers"
|
||||||
"github.com/matrix-org/dendrite/roomserver/storage"
|
"github.com/matrix-org/dendrite/roomserver/storage"
|
||||||
|
"github.com/matrix-org/dendrite/setup/base"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/dendrite/setup/jetstream"
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/dendrite/setup/process"
|
"github.com/matrix-org/dendrite/setup/process"
|
||||||
|
|
@ -39,6 +40,7 @@ type RoomserverInternalAPI struct {
|
||||||
*perform.Upgrader
|
*perform.Upgrader
|
||||||
*perform.Admin
|
*perform.Admin
|
||||||
ProcessContext *process.ProcessContext
|
ProcessContext *process.ProcessContext
|
||||||
|
Base *base.BaseDendrite
|
||||||
DB storage.Database
|
DB storage.Database
|
||||||
Cfg *config.RoomServer
|
Cfg *config.RoomServer
|
||||||
Cache caching.RoomServerCaches
|
Cache caching.RoomServerCaches
|
||||||
|
|
@ -56,33 +58,38 @@ type RoomserverInternalAPI struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRoomserverAPI(
|
func NewRoomserverAPI(
|
||||||
processCtx *process.ProcessContext, cfg *config.RoomServer, roomserverDB storage.Database,
|
base *base.BaseDendrite, roomserverDB storage.Database,
|
||||||
js nats.JetStreamContext, nc *nats.Conn, inputRoomEventTopic string,
|
js nats.JetStreamContext, nc *nats.Conn,
|
||||||
caches caching.RoomServerCaches, perspectiveServerNames []gomatrixserverlib.ServerName,
|
|
||||||
) *RoomserverInternalAPI {
|
) *RoomserverInternalAPI {
|
||||||
|
var perspectiveServerNames []gomatrixserverlib.ServerName
|
||||||
|
for _, kp := range base.Cfg.FederationAPI.KeyPerspectives {
|
||||||
|
perspectiveServerNames = append(perspectiveServerNames, kp.ServerName)
|
||||||
|
}
|
||||||
|
|
||||||
serverACLs := acls.NewServerACLs(roomserverDB)
|
serverACLs := acls.NewServerACLs(roomserverDB)
|
||||||
producer := &producers.RoomEventProducer{
|
producer := &producers.RoomEventProducer{
|
||||||
Topic: string(cfg.Matrix.JetStream.Prefixed(jetstream.OutputRoomEvent)),
|
Topic: string(base.Cfg.Global.JetStream.Prefixed(jetstream.OutputRoomEvent)),
|
||||||
JetStream: js,
|
JetStream: js,
|
||||||
ACLs: serverACLs,
|
ACLs: serverACLs,
|
||||||
}
|
}
|
||||||
a := &RoomserverInternalAPI{
|
a := &RoomserverInternalAPI{
|
||||||
ProcessContext: processCtx,
|
ProcessContext: base.ProcessContext,
|
||||||
DB: roomserverDB,
|
DB: roomserverDB,
|
||||||
Cfg: cfg,
|
Base: base,
|
||||||
Cache: caches,
|
Cfg: &base.Cfg.RoomServer,
|
||||||
ServerName: cfg.Matrix.ServerName,
|
Cache: base.Caches,
|
||||||
|
ServerName: base.Cfg.Global.ServerName,
|
||||||
PerspectiveServerNames: perspectiveServerNames,
|
PerspectiveServerNames: perspectiveServerNames,
|
||||||
InputRoomEventTopic: inputRoomEventTopic,
|
InputRoomEventTopic: base.Cfg.Global.JetStream.Prefixed(jetstream.InputRoomEvent),
|
||||||
OutputProducer: producer,
|
OutputProducer: producer,
|
||||||
JetStream: js,
|
JetStream: js,
|
||||||
NATSClient: nc,
|
NATSClient: nc,
|
||||||
Durable: cfg.Matrix.JetStream.Durable("RoomserverInputConsumer"),
|
Durable: base.Cfg.Global.JetStream.Durable("RoomserverInputConsumer"),
|
||||||
ServerACLs: serverACLs,
|
ServerACLs: serverACLs,
|
||||||
Queryer: &query.Queryer{
|
Queryer: &query.Queryer{
|
||||||
DB: roomserverDB,
|
DB: roomserverDB,
|
||||||
Cache: caches,
|
Cache: base.Caches,
|
||||||
ServerName: cfg.Matrix.ServerName,
|
ServerName: base.Cfg.Global.ServerName,
|
||||||
ServerACLs: serverACLs,
|
ServerACLs: serverACLs,
|
||||||
},
|
},
|
||||||
// perform-er structs get initialised when we have a federation sender to use
|
// perform-er structs get initialised when we have a federation sender to use
|
||||||
|
|
@ -98,8 +105,9 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
|
||||||
r.KeyRing = keyRing
|
r.KeyRing = keyRing
|
||||||
|
|
||||||
r.Inputer = &input.Inputer{
|
r.Inputer = &input.Inputer{
|
||||||
Cfg: r.Cfg,
|
Cfg: &r.Base.Cfg.RoomServer,
|
||||||
ProcessContext: r.ProcessContext,
|
Base: r.Base,
|
||||||
|
ProcessContext: r.Base.ProcessContext,
|
||||||
DB: r.DB,
|
DB: r.DB,
|
||||||
InputRoomEventTopic: r.InputRoomEventTopic,
|
InputRoomEventTopic: r.InputRoomEventTopic,
|
||||||
OutputProducer: r.OutputProducer,
|
OutputProducer: r.OutputProducer,
|
||||||
|
|
|
||||||
|
|
@ -50,14 +50,14 @@ func CheckForSoftFail(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("db.RoomNID: %w", err)
|
return false, fmt.Errorf("db.RoomNID: %w", err)
|
||||||
}
|
}
|
||||||
if roomInfo == nil || roomInfo.IsStub {
|
if roomInfo == nil || roomInfo.IsStub() {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then get the state entries for the current state snapshot.
|
// Then get the state entries for the current state snapshot.
|
||||||
// We'll use this to check if the event is allowed right now.
|
// We'll use this to check if the event is allowed right now.
|
||||||
roomState := state.NewStateResolution(db, roomInfo)
|
roomState := state.NewStateResolution(db, roomInfo)
|
||||||
authStateEntries, err = roomState.LoadStateAtSnapshot(ctx, roomInfo.StateSnapshotNID)
|
authStateEntries, err = roomState.LoadStateAtSnapshot(ctx, roomInfo.StateSnapshotNID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true, fmt.Errorf("roomState.LoadStateAtSnapshot: %w", err)
|
return true, fmt.Errorf("roomState.LoadStateAtSnapshot: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/roomserver/state"
|
"github.com/matrix-org/dendrite/roomserver/state"
|
||||||
"github.com/matrix-org/dendrite/roomserver/storage"
|
"github.com/matrix-org/dendrite/roomserver/storage"
|
||||||
"github.com/matrix-org/dendrite/roomserver/storage/shared"
|
"github.com/matrix-org/dendrite/roomserver/storage/shared"
|
||||||
|
"github.com/matrix-org/dendrite/roomserver/storage/tables"
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
|
@ -21,14 +22,14 @@ import (
|
||||||
// Move these to a more sensible place.
|
// Move these to a more sensible place.
|
||||||
|
|
||||||
func UpdateToInviteMembership(
|
func UpdateToInviteMembership(
|
||||||
mu *shared.MembershipUpdater, add *gomatrixserverlib.Event, updates []api.OutputEvent,
|
mu *shared.MembershipUpdater, add *types.Event, updates []api.OutputEvent,
|
||||||
roomVersion gomatrixserverlib.RoomVersion,
|
roomVersion gomatrixserverlib.RoomVersion,
|
||||||
) ([]api.OutputEvent, error) {
|
) ([]api.OutputEvent, error) {
|
||||||
// We may have already sent the invite to the user, either because we are
|
// We may have already sent the invite to the user, either because we are
|
||||||
// reprocessing this event, or because the we received this invite from a
|
// reprocessing this event, or because the we received this invite from a
|
||||||
// remote server via the federation invite API. In those cases we don't need
|
// remote server via the federation invite API. In those cases we don't need
|
||||||
// to send the event.
|
// to send the event.
|
||||||
needsSending, err := mu.SetToInvite(add)
|
needsSending, retired, err := mu.Update(tables.MembershipStateInvite, add)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -38,13 +39,23 @@ func UpdateToInviteMembership(
|
||||||
// room event stream. This ensures that the consumers only have to
|
// room event stream. This ensures that the consumers only have to
|
||||||
// consider a single stream of events when determining whether a user
|
// consider a single stream of events when determining whether a user
|
||||||
// is invited, rather than having to combine multiple streams themselves.
|
// is invited, rather than having to combine multiple streams themselves.
|
||||||
onie := api.OutputNewInviteEvent{
|
|
||||||
Event: add.Headered(roomVersion),
|
|
||||||
RoomVersion: roomVersion,
|
|
||||||
}
|
|
||||||
updates = append(updates, api.OutputEvent{
|
updates = append(updates, api.OutputEvent{
|
||||||
Type: api.OutputTypeNewInviteEvent,
|
Type: api.OutputTypeNewInviteEvent,
|
||||||
NewInviteEvent: &onie,
|
NewInviteEvent: &api.OutputNewInviteEvent{
|
||||||
|
Event: add.Headered(roomVersion),
|
||||||
|
RoomVersion: roomVersion,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for _, eventID := range retired {
|
||||||
|
updates = append(updates, api.OutputEvent{
|
||||||
|
Type: api.OutputTypeRetireInviteEvent,
|
||||||
|
RetireInviteEvent: &api.OutputRetireInviteEvent{
|
||||||
|
EventID: eventID,
|
||||||
|
Membership: gomatrixserverlib.Join,
|
||||||
|
RetiredByEventID: add.EventID(),
|
||||||
|
TargetUserID: *add.StateKey(),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return updates, nil
|
return updates, nil
|
||||||
|
|
@ -225,13 +236,34 @@ func LoadStateEvents(
|
||||||
func CheckServerAllowedToSeeEvent(
|
func CheckServerAllowedToSeeEvent(
|
||||||
ctx context.Context, db storage.Database, info *types.RoomInfo, eventID string, serverName gomatrixserverlib.ServerName, isServerInRoom bool,
|
ctx context.Context, db storage.Database, info *types.RoomInfo, eventID string, serverName gomatrixserverlib.ServerName, isServerInRoom bool,
|
||||||
) (bool, error) {
|
) (bool, error) {
|
||||||
|
stateAtEvent, err := db.GetHistoryVisibilityState(ctx, info, eventID, string(serverName))
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
// No error, so continue normally
|
||||||
|
case tables.OptimisationNotSupportedError:
|
||||||
|
// The database engine didn't support this optimisation, so fall back to using
|
||||||
|
// the old and slow method
|
||||||
|
stateAtEvent, err = slowGetHistoryVisibilityState(ctx, db, info, eventID, serverName)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Something else went wrong
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return auth.IsServerAllowed(serverName, isServerInRoom, stateAtEvent), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func slowGetHistoryVisibilityState(
|
||||||
|
ctx context.Context, db storage.Database, info *types.RoomInfo, eventID string, serverName gomatrixserverlib.ServerName,
|
||||||
|
) ([]*gomatrixserverlib.Event, error) {
|
||||||
roomState := state.NewStateResolution(db, info)
|
roomState := state.NewStateResolution(db, info)
|
||||||
stateEntries, err := roomState.LoadStateAtEvent(ctx, eventID)
|
stateEntries, err := roomState.LoadStateAtEvent(ctx, eventID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
return false, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return false, fmt.Errorf("roomState.LoadStateAtEvent: %w", err)
|
return nil, fmt.Errorf("roomState.LoadStateAtEvent: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract all of the event state key NIDs from the room state.
|
// Extract all of the event state key NIDs from the room state.
|
||||||
|
|
@ -243,7 +275,7 @@ func CheckServerAllowedToSeeEvent(
|
||||||
// Then request those state key NIDs from the database.
|
// Then request those state key NIDs from the database.
|
||||||
stateKeys, err := db.EventStateKeys(ctx, stateKeyNIDs)
|
stateKeys, err := db.EventStateKeys(ctx, stateKeyNIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("db.EventStateKeys: %w", err)
|
return nil, fmt.Errorf("db.EventStateKeys: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the event state key doesn't match the given servername
|
// If the event state key doesn't match the given servername
|
||||||
|
|
@ -266,15 +298,10 @@ func CheckServerAllowedToSeeEvent(
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(filteredEntries) == 0 {
|
if len(filteredEntries) == 0 {
|
||||||
return false, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
stateAtEvent, err := LoadStateEvents(ctx, db, filteredEntries)
|
return LoadStateEvents(ctx, db, filteredEntries)
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return auth.IsServerAllowed(serverName, isServerInRoom, stateAtEvent), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove this when we have tests to assert correctness of this function
|
// TODO: Remove this when we have tests to assert correctness of this function
|
||||||
|
|
@ -382,7 +409,7 @@ func QueryLatestEventsAndState(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if roomInfo == nil || roomInfo.IsStub {
|
if roomInfo == nil || roomInfo.IsStub() {
|
||||||
response.RoomExists = false
|
response.RoomExists = false
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/roomserver/internal/query"
|
"github.com/matrix-org/dendrite/roomserver/internal/query"
|
||||||
"github.com/matrix-org/dendrite/roomserver/producers"
|
"github.com/matrix-org/dendrite/roomserver/producers"
|
||||||
"github.com/matrix-org/dendrite/roomserver/storage"
|
"github.com/matrix-org/dendrite/roomserver/storage"
|
||||||
|
"github.com/matrix-org/dendrite/setup/base"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/dendrite/setup/jetstream"
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/dendrite/setup/process"
|
"github.com/matrix-org/dendrite/setup/process"
|
||||||
|
|
@ -69,6 +70,7 @@ import (
|
||||||
// or C.
|
// or C.
|
||||||
type Inputer struct {
|
type Inputer struct {
|
||||||
Cfg *config.RoomServer
|
Cfg *config.RoomServer
|
||||||
|
Base *base.BaseDendrite
|
||||||
ProcessContext *process.ProcessContext
|
ProcessContext *process.ProcessContext
|
||||||
DB storage.Database
|
DB storage.Database
|
||||||
NATSClient *nats.Conn
|
NATSClient *nats.Conn
|
||||||
|
|
@ -160,7 +162,9 @@ func (r *Inputer) startWorkerForRoom(roomID string) {
|
||||||
// will look to see if we have a worker for that room which has its
|
// will look to see if we have a worker for that room which has its
|
||||||
// own consumer. If we don't, we'll start one.
|
// own consumer. If we don't, we'll start one.
|
||||||
func (r *Inputer) Start() error {
|
func (r *Inputer) Start() error {
|
||||||
prometheus.MustRegister(roomserverInputBackpressure, processRoomEventDuration)
|
if r.Base.EnableMetrics {
|
||||||
|
prometheus.MustRegister(roomserverInputBackpressure, processRoomEventDuration)
|
||||||
|
}
|
||||||
_, err := r.JetStream.Subscribe(
|
_, err := r.JetStream.Subscribe(
|
||||||
"", // This is blank because we specified it in BindStream.
|
"", // This is blank because we specified it in BindStream.
|
||||||
func(m *nats.Msg) {
|
func(m *nats.Msg) {
|
||||||
|
|
|
||||||
|
|
@ -319,11 +319,9 @@ func (r *Inputer) processRoomEvent(
|
||||||
|
|
||||||
// if storing this event results in it being redacted then do so.
|
// if storing this event results in it being redacted then do so.
|
||||||
if !isRejected && redactedEventID == event.EventID() {
|
if !isRejected && redactedEventID == event.EventID() {
|
||||||
r, rerr := eventutil.RedactEvent(redactionEvent, event)
|
if err = eventutil.RedactEvent(redactionEvent, event); err != nil {
|
||||||
if rerr != nil {
|
|
||||||
return fmt.Errorf("eventutil.RedactEvent: %w", rerr)
|
return fmt.Errorf("eventutil.RedactEvent: %w", rerr)
|
||||||
}
|
}
|
||||||
event = r
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For outliers we can stop after we've stored the event itself as it
|
// For outliers we can stop after we've stored the event itself as it
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/dendrite/roomserver/internal/helpers"
|
"github.com/matrix-org/dendrite/roomserver/internal/helpers"
|
||||||
"github.com/matrix-org/dendrite/roomserver/storage/shared"
|
"github.com/matrix-org/dendrite/roomserver/storage/shared"
|
||||||
|
"github.com/matrix-org/dendrite/roomserver/storage/tables"
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/opentracing/opentracing-go"
|
"github.com/opentracing/opentracing-go"
|
||||||
|
|
@ -60,20 +61,14 @@ func (r *Inputer) updateMemberships(
|
||||||
var updates []api.OutputEvent
|
var updates []api.OutputEvent
|
||||||
|
|
||||||
for _, change := range changes {
|
for _, change := range changes {
|
||||||
var ae *gomatrixserverlib.Event
|
var ae *types.Event
|
||||||
var re *gomatrixserverlib.Event
|
var re *types.Event
|
||||||
targetUserNID := change.EventStateKeyNID
|
targetUserNID := change.EventStateKeyNID
|
||||||
if change.removedEventNID != 0 {
|
if change.removedEventNID != 0 {
|
||||||
ev, _ := helpers.EventMap(events).Lookup(change.removedEventNID)
|
re, _ = helpers.EventMap(events).Lookup(change.removedEventNID)
|
||||||
if ev != nil {
|
|
||||||
re = ev.Event
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if change.addedEventNID != 0 {
|
if change.addedEventNID != 0 {
|
||||||
ev, _ := helpers.EventMap(events).Lookup(change.addedEventNID)
|
ae, _ = helpers.EventMap(events).Lookup(change.addedEventNID)
|
||||||
if ev != nil {
|
|
||||||
ae = ev.Event
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if updates, err = r.updateMembership(updater, targetUserNID, re, ae, updates); err != nil {
|
if updates, err = r.updateMembership(updater, targetUserNID, re, ae, updates); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -85,30 +80,27 @@ func (r *Inputer) updateMemberships(
|
||||||
func (r *Inputer) updateMembership(
|
func (r *Inputer) updateMembership(
|
||||||
updater *shared.RoomUpdater,
|
updater *shared.RoomUpdater,
|
||||||
targetUserNID types.EventStateKeyNID,
|
targetUserNID types.EventStateKeyNID,
|
||||||
remove, add *gomatrixserverlib.Event,
|
remove, add *types.Event,
|
||||||
updates []api.OutputEvent,
|
updates []api.OutputEvent,
|
||||||
) ([]api.OutputEvent, error) {
|
) ([]api.OutputEvent, error) {
|
||||||
var err error
|
var err error
|
||||||
// Default the membership to Leave if no event was added or removed.
|
// Default the membership to Leave if no event was added or removed.
|
||||||
oldMembership := gomatrixserverlib.Leave
|
|
||||||
newMembership := gomatrixserverlib.Leave
|
newMembership := gomatrixserverlib.Leave
|
||||||
|
|
||||||
if remove != nil {
|
|
||||||
oldMembership, err = remove.Membership()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if add != nil {
|
if add != nil {
|
||||||
newMembership, err = add.Membership()
|
newMembership, err = add.Membership()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if oldMembership == newMembership && newMembership != gomatrixserverlib.Join {
|
|
||||||
// If the membership is the same then nothing changed and we can return
|
var targetLocal bool
|
||||||
// immediately, unless it's a Join update (e.g. profile update).
|
if add != nil {
|
||||||
return updates, nil
|
targetLocal = r.isLocalTarget(add)
|
||||||
|
}
|
||||||
|
|
||||||
|
mu, err := updater.MembershipUpdater(targetUserNID, targetLocal)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// In an ideal world, we shouldn't ever have "add" be nil and "remove" be
|
// In an ideal world, we shouldn't ever have "add" be nil and "remove" be
|
||||||
|
|
@ -120,17 +112,10 @@ func (r *Inputer) updateMembership(
|
||||||
// after a state reset, often thinking that the user was still joined to
|
// after a state reset, often thinking that the user was still joined to
|
||||||
// the room even though the room state said otherwise, and this would prevent
|
// the room even though the room state said otherwise, and this would prevent
|
||||||
// the user from being able to attempt to rejoin the room without modifying
|
// the user from being able to attempt to rejoin the room without modifying
|
||||||
// the database. So instead what we'll do is we'll just update the membership
|
// the database. So instead we're going to remove the membership from the
|
||||||
// table to say that the user is "leave" and we'll use the old event to
|
// database altogether, so that it doesn't create future problems.
|
||||||
// avoid nil pointer exceptions on the code path that follows.
|
if add == nil && remove != nil {
|
||||||
if add == nil {
|
return nil, mu.Delete()
|
||||||
add = remove
|
|
||||||
newMembership = gomatrixserverlib.Leave
|
|
||||||
}
|
|
||||||
|
|
||||||
mu, err := updater.MembershipUpdater(targetUserNID, r.isLocalTarget(add))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch newMembership {
|
switch newMembership {
|
||||||
|
|
@ -149,7 +134,7 @@ func (r *Inputer) updateMembership(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Inputer) isLocalTarget(event *gomatrixserverlib.Event) bool {
|
func (r *Inputer) isLocalTarget(event *types.Event) bool {
|
||||||
isTargetLocalUser := false
|
isTargetLocalUser := false
|
||||||
if statekey := event.StateKey(); statekey != nil {
|
if statekey := event.StateKey(); statekey != nil {
|
||||||
_, domain, _ := gomatrixserverlib.SplitID('@', *statekey)
|
_, domain, _ := gomatrixserverlib.SplitID('@', *statekey)
|
||||||
|
|
@ -159,81 +144,61 @@ func (r *Inputer) isLocalTarget(event *gomatrixserverlib.Event) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateToJoinMembership(
|
func updateToJoinMembership(
|
||||||
mu *shared.MembershipUpdater, add *gomatrixserverlib.Event, updates []api.OutputEvent,
|
mu *shared.MembershipUpdater, add *types.Event, updates []api.OutputEvent,
|
||||||
) ([]api.OutputEvent, error) {
|
) ([]api.OutputEvent, error) {
|
||||||
// If the user is already marked as being joined, we call SetToJoin to update
|
|
||||||
// the event ID then we can return immediately. Retired is ignored as there
|
|
||||||
// is no invite event to retire.
|
|
||||||
if mu.IsJoin() {
|
|
||||||
_, err := mu.SetToJoin(add.Sender(), add.EventID(), true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return updates, nil
|
|
||||||
}
|
|
||||||
// When we mark a user as being joined we will invalidate any invites that
|
// When we mark a user as being joined we will invalidate any invites that
|
||||||
// are active for that user. We notify the consumers that the invites have
|
// are active for that user. We notify the consumers that the invites have
|
||||||
// been retired using a special event, even though they could infer this
|
// been retired using a special event, even though they could infer this
|
||||||
// by studying the state changes in the room event stream.
|
// by studying the state changes in the room event stream.
|
||||||
retired, err := mu.SetToJoin(add.Sender(), add.EventID(), false)
|
_, retired, err := mu.Update(tables.MembershipStateJoin, add)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, eventID := range retired {
|
for _, eventID := range retired {
|
||||||
orie := api.OutputRetireInviteEvent{
|
|
||||||
EventID: eventID,
|
|
||||||
Membership: gomatrixserverlib.Join,
|
|
||||||
RetiredByEventID: add.EventID(),
|
|
||||||
TargetUserID: *add.StateKey(),
|
|
||||||
}
|
|
||||||
updates = append(updates, api.OutputEvent{
|
updates = append(updates, api.OutputEvent{
|
||||||
Type: api.OutputTypeRetireInviteEvent,
|
Type: api.OutputTypeRetireInviteEvent,
|
||||||
RetireInviteEvent: &orie,
|
RetireInviteEvent: &api.OutputRetireInviteEvent{
|
||||||
|
EventID: eventID,
|
||||||
|
Membership: gomatrixserverlib.Join,
|
||||||
|
RetiredByEventID: add.EventID(),
|
||||||
|
TargetUserID: *add.StateKey(),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return updates, nil
|
return updates, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateToLeaveMembership(
|
func updateToLeaveMembership(
|
||||||
mu *shared.MembershipUpdater, add *gomatrixserverlib.Event,
|
mu *shared.MembershipUpdater, add *types.Event,
|
||||||
newMembership string, updates []api.OutputEvent,
|
newMembership string, updates []api.OutputEvent,
|
||||||
) ([]api.OutputEvent, error) {
|
) ([]api.OutputEvent, error) {
|
||||||
// If the user is already neither joined, nor invited to the room then we
|
|
||||||
// can return immediately.
|
|
||||||
if mu.IsLeave() {
|
|
||||||
return updates, nil
|
|
||||||
}
|
|
||||||
// When we mark a user as having left we will invalidate any invites that
|
// When we mark a user as having left we will invalidate any invites that
|
||||||
// are active for that user. We notify the consumers that the invites have
|
// are active for that user. We notify the consumers that the invites have
|
||||||
// been retired using a special event, even though they could infer this
|
// been retired using a special event, even though they could infer this
|
||||||
// by studying the state changes in the room event stream.
|
// by studying the state changes in the room event stream.
|
||||||
retired, err := mu.SetToLeave(add.Sender(), add.EventID())
|
_, retired, err := mu.Update(tables.MembershipStateLeaveOrBan, add)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, eventID := range retired {
|
for _, eventID := range retired {
|
||||||
orie := api.OutputRetireInviteEvent{
|
|
||||||
EventID: eventID,
|
|
||||||
Membership: newMembership,
|
|
||||||
RetiredByEventID: add.EventID(),
|
|
||||||
TargetUserID: *add.StateKey(),
|
|
||||||
}
|
|
||||||
updates = append(updates, api.OutputEvent{
|
updates = append(updates, api.OutputEvent{
|
||||||
Type: api.OutputTypeRetireInviteEvent,
|
Type: api.OutputTypeRetireInviteEvent,
|
||||||
RetireInviteEvent: &orie,
|
RetireInviteEvent: &api.OutputRetireInviteEvent{
|
||||||
|
EventID: eventID,
|
||||||
|
Membership: newMembership,
|
||||||
|
RetiredByEventID: add.EventID(),
|
||||||
|
TargetUserID: *add.StateKey(),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return updates, nil
|
return updates, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateToKnockMembership(
|
func updateToKnockMembership(
|
||||||
mu *shared.MembershipUpdater, add *gomatrixserverlib.Event, updates []api.OutputEvent,
|
mu *shared.MembershipUpdater, add *types.Event, updates []api.OutputEvent,
|
||||||
) ([]api.OutputEvent, error) {
|
) ([]api.OutputEvent, error) {
|
||||||
if mu.IsLeave() {
|
if _, _, err := mu.Update(tables.MembershipStateKnock, add); err != nil {
|
||||||
_, err := mu.SetToKnock(add)
|
return nil, err
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return updates, nil
|
return updates, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,10 +48,6 @@ func TestSingleTransactionOnInput(t *testing.T) {
|
||||||
Kind: api.KindOutlier, // don't panic if we generate an output event
|
Kind: api.KindOutlier, // don't panic if we generate an output event
|
||||||
Event: event.Headered(gomatrixserverlib.RoomVersionV6),
|
Event: event.Headered(gomatrixserverlib.RoomVersionV6),
|
||||||
}
|
}
|
||||||
cache, err := caching.NewInMemoryLRUCache(false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
db, err := storage.Open(
|
db, err := storage.Open(
|
||||||
nil,
|
nil,
|
||||||
&config.DatabaseOptions{
|
&config.DatabaseOptions{
|
||||||
|
|
@ -59,7 +55,7 @@ func TestSingleTransactionOnInput(t *testing.T) {
|
||||||
MaxOpenConnections: 1,
|
MaxOpenConnections: 1,
|
||||||
MaxIdleConnections: 1,
|
MaxIdleConnections: 1,
|
||||||
},
|
},
|
||||||
cache,
|
caching.NewRistrettoCache(8*1024*1024, time.Hour, false),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("PostgreSQL not available (%s), skipping", err)
|
t.Logf("PostgreSQL not available (%s), skipping", err)
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func (r *Admin) PerformAdminEvacuateRoom(
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if roomInfo == nil || roomInfo.IsStub {
|
if roomInfo == nil || roomInfo.IsStub() {
|
||||||
res.Error = &api.PerformError{
|
res.Error = &api.PerformError{
|
||||||
Code: api.PerformErrorNoRoom,
|
Code: api.PerformErrorNoRoom,
|
||||||
Msg: fmt.Sprintf("Room %s not found", req.RoomID),
|
Msg: fmt.Sprintf("Room %s not found", req.RoomID),
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ func (r *Backfiller) PerformBackfill(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if info == nil || info.IsStub {
|
if info == nil || info.IsStub() {
|
||||||
return fmt.Errorf("PerformBackfill: missing room info for room %s", request.RoomID)
|
return fmt.Errorf("PerformBackfill: missing room info for room %s", request.RoomID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,7 +106,7 @@ func (r *Backfiller) backfillViaFederation(ctx context.Context, req *api.Perform
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if info == nil || info.IsStub {
|
if info == nil || info.IsStub() {
|
||||||
return fmt.Errorf("backfillViaFederation: missing room info for room %s", req.RoomID)
|
return fmt.Errorf("backfillViaFederation: missing room info for room %s", req.RoomID)
|
||||||
}
|
}
|
||||||
requester := newBackfillRequester(r.DB, r.FSAPI, r.ServerName, req.BackwardsExtremities, r.PreferServers)
|
requester := newBackfillRequester(r.DB, r.FSAPI, r.ServerName, req.BackwardsExtremities, r.PreferServers)
|
||||||
|
|
@ -434,7 +434,7 @@ FindSuccessor:
|
||||||
logrus.WithError(err).WithField("room_id", roomID).Error("ServersAtEvent: failed to get RoomInfo for room")
|
logrus.WithError(err).WithField("room_id", roomID).Error("ServersAtEvent: failed to get RoomInfo for room")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if info == nil || info.IsStub {
|
if info == nil || info.IsStub() {
|
||||||
logrus.WithField("room_id", roomID).Error("ServersAtEvent: failed to get RoomInfo for room, room is missing")
|
logrus.WithField("room_id", roomID).Error("ServersAtEvent: failed to get RoomInfo for room, room is missing")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -593,12 +593,11 @@ func persistEvents(ctx context.Context, db storage.Database, events []*gomatrixs
|
||||||
// redacted, which we don't care about since we aren't returning it in this backfill.
|
// redacted, which we don't care about since we aren't returning it in this backfill.
|
||||||
if redactedEventID == ev.EventID() {
|
if redactedEventID == ev.EventID() {
|
||||||
eventToRedact := ev.Unwrap()
|
eventToRedact := ev.Unwrap()
|
||||||
redactedEvent, err := eventutil.RedactEvent(redactionEvent, eventToRedact)
|
if err := eventutil.RedactEvent(redactionEvent, eventToRedact); err != nil {
|
||||||
if err != nil {
|
|
||||||
logrus.WithError(err).WithField("event_id", ev.EventID()).Error("Failed to redact event")
|
logrus.WithError(err).WithField("event_id", ev.EventID()).Error("Failed to redact event")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ev = redactedEvent.Headered(ev.RoomVersion)
|
ev = eventToRedact.Headered(ev.RoomVersion)
|
||||||
events[j] = ev
|
events[j] = ev
|
||||||
}
|
}
|
||||||
backfilledEventMap[ev.EventID()] = types.Event{
|
backfilledEventMap[ev.EventID()] = types.Event{
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ func (r *InboundPeeker) PerformInboundPeek(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if info == nil || info.IsStub {
|
if info == nil || info.IsStub() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
response.RoomExists = true
|
response.RoomExists = true
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,13 @@ type Inviter struct {
|
||||||
Inputer *input.Inputer
|
Inputer *input.Inputer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint:gocyclo
|
||||||
func (r *Inviter) PerformInvite(
|
func (r *Inviter) PerformInvite(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req *api.PerformInviteRequest,
|
req *api.PerformInviteRequest,
|
||||||
res *api.PerformInviteResponse,
|
res *api.PerformInviteResponse,
|
||||||
) ([]api.OutputEvent, error) {
|
) ([]api.OutputEvent, error) {
|
||||||
|
var outputUpdates []api.OutputEvent
|
||||||
event := req.Event
|
event := req.Event
|
||||||
if event.StateKey() == nil {
|
if event.StateKey() == nil {
|
||||||
return nil, fmt.Errorf("invite must be a state event")
|
return nil, fmt.Errorf("invite must be a state event")
|
||||||
|
|
@ -66,6 +68,13 @@ func (r *Inviter) PerformInvite(
|
||||||
}
|
}
|
||||||
isTargetLocal := domain == r.Cfg.Matrix.ServerName
|
isTargetLocal := domain == r.Cfg.Matrix.ServerName
|
||||||
isOriginLocal := event.Origin() == r.Cfg.Matrix.ServerName
|
isOriginLocal := event.Origin() == r.Cfg.Matrix.ServerName
|
||||||
|
if !isOriginLocal && !isTargetLocal {
|
||||||
|
res.Error = &api.PerformError{
|
||||||
|
Code: api.PerformErrorBadRequest,
|
||||||
|
Msg: "The invite must be either from or to a local user",
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
logger := util.GetLogger(ctx).WithFields(map[string]interface{}{
|
logger := util.GetLogger(ctx).WithFields(map[string]interface{}{
|
||||||
"inviter": event.Sender(),
|
"inviter": event.Sender(),
|
||||||
|
|
@ -97,6 +106,34 @@ func (r *Inviter) PerformInvite(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateMembershipTableManually := func() ([]api.OutputEvent, error) {
|
||||||
|
var updater *shared.MembershipUpdater
|
||||||
|
if updater, err = r.DB.MembershipUpdater(ctx, roomID, targetUserID, isTargetLocal, req.RoomVersion); err != nil {
|
||||||
|
return nil, fmt.Errorf("r.DB.MembershipUpdater: %w", err)
|
||||||
|
}
|
||||||
|
outputUpdates, err = helpers.UpdateToInviteMembership(updater, &types.Event{
|
||||||
|
EventNID: 0,
|
||||||
|
Event: event.Unwrap(),
|
||||||
|
}, outputUpdates, req.Event.RoomVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("updateToInviteMembership: %w", err)
|
||||||
|
}
|
||||||
|
if err = updater.Commit(); err != nil {
|
||||||
|
return nil, fmt.Errorf("updater.Commit: %w", err)
|
||||||
|
}
|
||||||
|
logger.Debugf("updated membership to invite and sending invite OutputEvent")
|
||||||
|
return outputUpdates, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info == nil || info.IsStub()) && !isOriginLocal && isTargetLocal {
|
||||||
|
// The invite came in over federation for a room that we don't know about
|
||||||
|
// yet. We need to handle this a bit differently to most invites because
|
||||||
|
// we don't know the room state, therefore the roomserver can't process
|
||||||
|
// an input event. Instead we will update the membership table with the
|
||||||
|
// new invite and generate an output event.
|
||||||
|
return updateMembershipTableManually()
|
||||||
|
}
|
||||||
|
|
||||||
var isAlreadyJoined bool
|
var isAlreadyJoined bool
|
||||||
if info != nil {
|
if info != nil {
|
||||||
_, _, isAlreadyJoined, _, err = r.DB.GetMembership(ctx, info.RoomNID, *event.StateKey())
|
_, _, isAlreadyJoined, _, err = r.DB.GetMembership(ctx, info.RoomNID, *event.StateKey())
|
||||||
|
|
@ -140,31 +177,13 @@ func (r *Inviter) PerformInvite(
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the invite originated remotely then we can't send an
|
||||||
|
// InputRoomEvent for the invite as it will never pass auth checks
|
||||||
|
// due to lacking room state, but we still need to tell the client
|
||||||
|
// about the invite so we can accept it, hence we return an output
|
||||||
|
// event to send to the Sync API.
|
||||||
if !isOriginLocal {
|
if !isOriginLocal {
|
||||||
// The invite originated over federation. Process the membership
|
return updateMembershipTableManually()
|
||||||
// update, which will notify the sync API etc about the incoming
|
|
||||||
// invite. We do NOT send an InputRoomEvent for the invite as it
|
|
||||||
// will never pass auth checks due to lacking room state, but we
|
|
||||||
// still need to tell the client about the invite so we can accept
|
|
||||||
// it, hence we return an output event to send to the sync api.
|
|
||||||
var updater *shared.MembershipUpdater
|
|
||||||
updater, err = r.DB.MembershipUpdater(ctx, roomID, targetUserID, isTargetLocal, req.RoomVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("r.DB.MembershipUpdater: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
unwrapped := event.Unwrap()
|
|
||||||
var outputUpdates []api.OutputEvent
|
|
||||||
outputUpdates, err = helpers.UpdateToInviteMembership(updater, unwrapped, nil, req.Event.RoomVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("updateToInviteMembership: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = updater.Commit(); err != nil {
|
|
||||||
return nil, fmt.Errorf("updater.Commit: %w", err)
|
|
||||||
}
|
|
||||||
logger.Debugf("updated membership to invite and sending invite OutputEvent")
|
|
||||||
return outputUpdates, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The invite originated locally. Therefore we have a responsibility to
|
// The invite originated locally. Therefore we have a responsibility to
|
||||||
|
|
@ -229,12 +248,11 @@ func (r *Inviter) PerformInvite(
|
||||||
Code: api.PerformErrorNotAllowed,
|
Code: api.PerformErrorNotAllowed,
|
||||||
}
|
}
|
||||||
logger.WithError(err).WithField("event_id", event.EventID()).Error("r.InputRoomEvents failed")
|
logger.WithError(err).WithField("event_id", event.EventID()).Error("r.InputRoomEvents failed")
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't notify the sync api of this event in the same way as a federated invite so the invitee
|
// Don't notify the sync api of this event in the same way as a federated invite so the invitee
|
||||||
// gets the invite, as the roomserver will do this when it processes the m.room.member invite.
|
// gets the invite, as the roomserver will do this when it processes the m.room.member invite.
|
||||||
return nil, nil
|
return outputUpdates, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildInviteStrippedState(
|
func buildInviteStrippedState(
|
||||||
|
|
@ -258,7 +276,7 @@ func buildInviteStrippedState(
|
||||||
}
|
}
|
||||||
roomState := state.NewStateResolution(db, info)
|
roomState := state.NewStateResolution(db, info)
|
||||||
stateEntries, err := roomState.LoadStateAtSnapshotForStringTuples(
|
stateEntries, err := roomState.LoadStateAtSnapshotForStringTuples(
|
||||||
ctx, info.StateSnapshotNID, stateWanted,
|
ctx, info.StateSnapshotNID(), stateWanted,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -268,21 +268,19 @@ func (r *Joiner) performJoinRoomByID(
|
||||||
case nil:
|
case nil:
|
||||||
// The room join is local. Send the new join event into the
|
// The room join is local. Send the new join event into the
|
||||||
// roomserver. First of all check that the user isn't already
|
// roomserver. First of all check that the user isn't already
|
||||||
// a member of the room.
|
// a member of the room. This is best-effort (as in we won't
|
||||||
alreadyJoined := false
|
// fail if we can't find the existing membership) because there
|
||||||
for _, se := range buildRes.StateEvents {
|
// is really no harm in just sending another membership event.
|
||||||
if !se.StateKeyEquals(userID) {
|
membershipReq := &api.QueryMembershipForUserRequest{
|
||||||
continue
|
RoomID: req.RoomIDOrAlias,
|
||||||
}
|
UserID: userID,
|
||||||
if membership, merr := se.Membership(); merr == nil {
|
|
||||||
alreadyJoined = (membership == gomatrixserverlib.Join)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
membershipRes := &api.QueryMembershipForUserResponse{}
|
||||||
|
_ = r.Queryer.QueryMembershipForUser(ctx, membershipReq, membershipRes)
|
||||||
|
|
||||||
// If we haven't already joined the room then send an event
|
// If we haven't already joined the room then send an event
|
||||||
// into the room changing our membership status.
|
// into the room changing our membership status.
|
||||||
if !alreadyJoined {
|
if !membershipRes.RoomExists || !membershipRes.IsInRoom {
|
||||||
inputReq := rsAPI.InputRoomEventsRequest{
|
inputReq := rsAPI.InputRoomEventsRequest{
|
||||||
InputRoomEvents: []rsAPI.InputRoomEvent{
|
InputRoomEvents: []rsAPI.InputRoomEvent{
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -228,14 +228,14 @@ func (r *Leaver) performFederatedRejectInvite(
|
||||||
util.GetLogger(ctx).WithError(err).Errorf("failed to get MembershipUpdater, still retiring invite event")
|
util.GetLogger(ctx).WithError(err).Errorf("failed to get MembershipUpdater, still retiring invite event")
|
||||||
}
|
}
|
||||||
if updater != nil {
|
if updater != nil {
|
||||||
if _, err = updater.SetToLeave(req.UserID, eventID); err != nil {
|
if err = updater.Delete(); err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Errorf("failed to set membership to leave, still retiring invite event")
|
util.GetLogger(ctx).WithError(err).Errorf("failed to delete membership, still retiring invite event")
|
||||||
if err = updater.Rollback(); err != nil {
|
if err = updater.Rollback(); err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Errorf("failed to rollback membership leave, still retiring invite event")
|
util.GetLogger(ctx).WithError(err).Errorf("failed to rollback deleting membership, still retiring invite event")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err = updater.Commit(); err != nil {
|
if err = updater.Commit(); err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Errorf("failed to commit membership update, still retiring invite event")
|
util.GetLogger(ctx).WithError(err).Errorf("failed to commit deleting membership, still retiring invite event")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ package query
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -61,7 +62,7 @@ func (r *Queryer) QueryStateAfterEvents(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if info == nil || info.IsStub {
|
if info == nil || info.IsStub() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,6 +232,9 @@ func (r *Queryer) QueryMembershipsForRoom(
|
||||||
var eventNIDs []types.EventNID
|
var eventNIDs []types.EventNID
|
||||||
eventNIDs, err = r.DB.GetMembershipEventNIDsForRoom(ctx, info.RoomNID, request.JoinedOnly, request.LocalOnly)
|
eventNIDs, err = r.DB.GetMembershipEventNIDsForRoom(ctx, info.RoomNID, request.JoinedOnly, request.LocalOnly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return fmt.Errorf("r.DB.GetMembershipEventNIDsForRoom: %w", err)
|
return fmt.Errorf("r.DB.GetMembershipEventNIDsForRoom: %w", err)
|
||||||
}
|
}
|
||||||
events, err = r.DB.Events(ctx, eventNIDs)
|
events, err = r.DB.Events(ctx, eventNIDs)
|
||||||
|
|
@ -266,6 +270,9 @@ func (r *Queryer) QueryMembershipsForRoom(
|
||||||
var eventNIDs []types.EventNID
|
var eventNIDs []types.EventNID
|
||||||
eventNIDs, err = r.DB.GetMembershipEventNIDsForRoom(ctx, info.RoomNID, request.JoinedOnly, false)
|
eventNIDs, err = r.DB.GetMembershipEventNIDsForRoom(ctx, info.RoomNID, request.JoinedOnly, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -301,7 +308,7 @@ func (r *Queryer) QueryServerJoinedToRoom(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("r.DB.RoomInfo: %w", err)
|
return fmt.Errorf("r.DB.RoomInfo: %w", err)
|
||||||
}
|
}
|
||||||
if info == nil || info.IsStub {
|
if info == nil || info.IsStub() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
response.RoomExists = true
|
response.RoomExists = true
|
||||||
|
|
@ -389,7 +396,7 @@ func (r *Queryer) QueryMissingEvents(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if info == nil || info.IsStub {
|
if info == nil || info.IsStub() {
|
||||||
return fmt.Errorf("missing RoomInfo for room %s", events[0].RoomID())
|
return fmt.Errorf("missing RoomInfo for room %s", events[0].RoomID())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -428,7 +435,7 @@ func (r *Queryer) QueryStateAndAuthChain(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if info == nil || info.IsStub {
|
if info == nil || info.IsStub() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
response.RoomExists = true
|
response.RoomExists = true
|
||||||
|
|
@ -773,7 +780,7 @@ func (r *Queryer) QueryRestrictedJoinAllowed(ctx context.Context, req *api.Query
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("r.DB.RoomInfo: %w", err)
|
return fmt.Errorf("r.DB.RoomInfo: %w", err)
|
||||||
}
|
}
|
||||||
if roomInfo == nil || roomInfo.IsStub {
|
if roomInfo == nil || roomInfo.IsStub() {
|
||||||
return nil // fmt.Errorf("room %q doesn't exist or is stub room", req.RoomID)
|
return nil // fmt.Errorf("room %q doesn't exist or is stub room", req.RoomID)
|
||||||
}
|
}
|
||||||
// If the room version doesn't allow restricted joins then don't
|
// If the room version doesn't allow restricted joins then don't
|
||||||
|
|
@ -836,7 +843,7 @@ func (r *Queryer) QueryRestrictedJoinAllowed(ctx context.Context, req *api.Query
|
||||||
// See if the room exists. If it doesn't exist or if it's a stub
|
// See if the room exists. If it doesn't exist or if it's a stub
|
||||||
// room entry then we can't check memberships.
|
// room entry then we can't check memberships.
|
||||||
targetRoomInfo, err := r.DB.RoomInfo(ctx, rule.RoomID)
|
targetRoomInfo, err := r.DB.RoomInfo(ctx, rule.RoomID)
|
||||||
if err != nil || targetRoomInfo == nil || targetRoomInfo.IsStub {
|
if err != nil || targetRoomInfo == nil || targetRoomInfo.IsStub() {
|
||||||
res.Resident = false
|
res.Resident = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,10 @@ package roomserver
|
||||||
import (
|
import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/dendrite/roomserver/inthttp"
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/roomserver/internal"
|
"github.com/matrix-org/dendrite/roomserver/internal"
|
||||||
|
"github.com/matrix-org/dendrite/roomserver/inthttp"
|
||||||
"github.com/matrix-org/dendrite/roomserver/storage"
|
"github.com/matrix-org/dendrite/roomserver/storage"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
"github.com/matrix-org/dendrite/setup/base"
|
||||||
"github.com/matrix-org/dendrite/setup/jetstream"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -40,11 +37,6 @@ func NewInternalAPI(
|
||||||
) api.RoomserverInternalAPI {
|
) api.RoomserverInternalAPI {
|
||||||
cfg := &base.Cfg.RoomServer
|
cfg := &base.Cfg.RoomServer
|
||||||
|
|
||||||
var perspectiveServerNames []gomatrixserverlib.ServerName
|
|
||||||
for _, kp := range base.Cfg.FederationAPI.KeyPerspectives {
|
|
||||||
perspectiveServerNames = append(perspectiveServerNames, kp.ServerName)
|
|
||||||
}
|
|
||||||
|
|
||||||
roomserverDB, err := storage.Open(base, &cfg.Database, base.Caches)
|
roomserverDB, err := storage.Open(base, &cfg.Database, base.Caches)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Panicf("failed to connect to room server db")
|
logrus.WithError(err).Panicf("failed to connect to room server db")
|
||||||
|
|
@ -53,8 +45,6 @@ func NewInternalAPI(
|
||||||
js, nc := base.NATS.Prepare(base.ProcessContext, &cfg.Matrix.JetStream)
|
js, nc := base.NATS.Prepare(base.ProcessContext, &cfg.Matrix.JetStream)
|
||||||
|
|
||||||
return internal.NewRoomserverAPI(
|
return internal.NewRoomserverAPI(
|
||||||
base.ProcessContext, cfg, roomserverDB, js, nc,
|
base, roomserverDB, js, nc,
|
||||||
cfg.Matrix.JetStream.Prefixed(jetstream.InputRoomEvent),
|
|
||||||
base.Caches, perspectiveServerNames,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
69
roomserver/roomserver_test.go
Normal file
69
roomserver/roomserver_test.go
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
package roomserver_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/roomserver"
|
||||||
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
|
"github.com/matrix-org/dendrite/roomserver/storage"
|
||||||
|
"github.com/matrix-org/dendrite/setup/base"
|
||||||
|
"github.com/matrix-org/dendrite/test"
|
||||||
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mustCreateDatabase(t *testing.T, dbType test.DBType) (*base.BaseDendrite, storage.Database, func()) {
|
||||||
|
base, close := testrig.CreateBaseDendrite(t, dbType)
|
||||||
|
db, err := storage.Open(base, &base.Cfg.KeyServer.Database, base.Caches)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create Database: %v", err)
|
||||||
|
}
|
||||||
|
return base, db, close
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_SharedUsers(t *testing.T) {
|
||||||
|
alice := test.NewUser(t)
|
||||||
|
bob := test.NewUser(t)
|
||||||
|
room := test.NewRoom(t, alice, test.RoomPreset(test.PresetTrustedPrivateChat))
|
||||||
|
|
||||||
|
// Invite and join Bob
|
||||||
|
room.CreateAndInsert(t, alice, gomatrixserverlib.MRoomMember, map[string]interface{}{
|
||||||
|
"membership": "invite",
|
||||||
|
}, test.WithStateKey(bob.ID))
|
||||||
|
room.CreateAndInsert(t, bob, gomatrixserverlib.MRoomMember, map[string]interface{}{
|
||||||
|
"membership": "join",
|
||||||
|
}, test.WithStateKey(bob.ID))
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
|
base, _, close := mustCreateDatabase(t, dbType)
|
||||||
|
defer close()
|
||||||
|
|
||||||
|
rsAPI := roomserver.NewInternalAPI(base)
|
||||||
|
// SetFederationAPI starts the room event input consumer
|
||||||
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
|
// Create the room
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", nil, false); err != nil {
|
||||||
|
t.Fatalf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query the shared users for Alice, there should only be Bob.
|
||||||
|
// This is used by the SyncAPI keychange consumer.
|
||||||
|
res := &api.QuerySharedUsersResponse{}
|
||||||
|
if err := rsAPI.QuerySharedUsers(ctx, &api.QuerySharedUsersRequest{UserID: alice.ID}, res); err != nil {
|
||||||
|
t.Fatalf("unable to query known users: %v", err)
|
||||||
|
}
|
||||||
|
if _, ok := res.UserIDsToCount[bob.ID]; !ok {
|
||||||
|
t.Fatalf("expected to find %s in shared users, but didn't: %+v", bob.ID, res.UserIDsToCount)
|
||||||
|
}
|
||||||
|
// Also verify that we get the expected result when specifying OtherUserIDs.
|
||||||
|
// This is used by the SyncAPI when getting device list changes.
|
||||||
|
if err := rsAPI.QuerySharedUsers(ctx, &api.QuerySharedUsersRequest{UserID: alice.ID, OtherUserIDs: []string{bob.ID}}, res); err != nil {
|
||||||
|
t.Fatalf("unable to query known users: %v", err)
|
||||||
|
}
|
||||||
|
if _, ok := res.UserIDsToCount[bob.ID]; !ok {
|
||||||
|
t.Fatalf("expected to find %s in shared users, but didn't: %+v", bob.ID, res.UserIDsToCount)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -110,7 +110,30 @@ func (v *StateResolution) LoadStateAtEvent(
|
||||||
|
|
||||||
snapshotNID, err := v.db.SnapshotNIDFromEventID(ctx, eventID)
|
snapshotNID, err := v.db.SnapshotNIDFromEventID(ctx, eventID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("LoadStateAtEvent.SnapshotNIDFromEventID failed for event %s : %s", eventID, err)
|
return nil, fmt.Errorf("LoadStateAtEvent.SnapshotNIDFromEventID failed for event %s : %w", eventID, err)
|
||||||
|
}
|
||||||
|
if snapshotNID == 0 {
|
||||||
|
return nil, fmt.Errorf("LoadStateAtEvent.SnapshotNIDFromEventID(%s) returned 0 NID, was this event stored?", eventID)
|
||||||
|
}
|
||||||
|
|
||||||
|
stateEntries, err := v.LoadStateAtSnapshot(ctx, snapshotNID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return stateEntries, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadStateAtEvent loads the full state of a room before a particular event.
|
||||||
|
func (v *StateResolution) LoadStateAtEventForHistoryVisibility(
|
||||||
|
ctx context.Context, eventID string,
|
||||||
|
) ([]types.StateEntry, error) {
|
||||||
|
span, ctx := opentracing.StartSpanFromContext(ctx, "StateResolution.LoadStateAtEvent")
|
||||||
|
defer span.Finish()
|
||||||
|
|
||||||
|
snapshotNID, err := v.db.SnapshotNIDFromEventID(ctx, eventID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("LoadStateAtEvent.SnapshotNIDFromEventID failed for event %s : %w", eventID, err)
|
||||||
}
|
}
|
||||||
if snapshotNID == 0 {
|
if snapshotNID == 0 {
|
||||||
return nil, fmt.Errorf("LoadStateAtEvent.SnapshotNIDFromEventID(%s) returned 0 NID, was this event stored?", eventID)
|
return nil, fmt.Errorf("LoadStateAtEvent.SnapshotNIDFromEventID(%s) returned 0 NID, was this event stored?", eventID)
|
||||||
|
|
@ -1027,7 +1050,7 @@ func (v *StateResolution) loadStateEvents(
|
||||||
|
|
||||||
result := make([]*gomatrixserverlib.Event, 0, len(entries))
|
result := make([]*gomatrixserverlib.Event, 0, len(entries))
|
||||||
eventEntries := make([]types.StateEntry, 0, len(entries))
|
eventEntries := make([]types.StateEntry, 0, len(entries))
|
||||||
eventNIDs := make([]types.EventNID, 0, len(entries))
|
eventNIDs := make(types.EventNIDs, 0, len(entries))
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if e, ok := v.events[entry.EventNID]; ok {
|
if e, ok := v.events[entry.EventNID]; ok {
|
||||||
result = append(result, e)
|
result = append(result, e)
|
||||||
|
|
|
||||||
|
|
@ -166,4 +166,6 @@ type Database interface {
|
||||||
GetKnownRooms(ctx context.Context) ([]string, error)
|
GetKnownRooms(ctx context.Context) ([]string, error)
|
||||||
// ForgetRoom sets a flag in the membership table, that the user wishes to forget a specific room
|
// ForgetRoom sets a flag in the membership table, that the user wishes to forget a specific room
|
||||||
ForgetRoom(ctx context.Context, userID, roomID string, forget bool) error
|
ForgetRoom(ctx context.Context, userID, roomID string, forget bool) error
|
||||||
|
|
||||||
|
GetHistoryVisibilityState(ctx context.Context, roomInfo *types.RoomInfo, eventID string, domain string) ([]*gomatrixserverlib.Event, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,32 +15,21 @@
|
||||||
package deltas
|
package deltas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
|
||||||
"github.com/pressly/goose"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadFromGoose() {
|
func UpAddForgottenColumn(ctx context.Context, tx *sql.Tx) error {
|
||||||
goose.AddMigration(UpAddForgottenColumn, DownAddForgottenColumn)
|
_, err := tx.ExecContext(ctx, `ALTER TABLE roomserver_membership ADD COLUMN IF NOT EXISTS forgotten BOOLEAN NOT NULL DEFAULT false;`)
|
||||||
goose.AddMigration(UpStateBlocksRefactor, DownStateBlocksRefactor)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadAddForgottenColumn(m *sqlutil.Migrations) {
|
|
||||||
m.AddMigration(UpAddForgottenColumn, DownAddForgottenColumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpAddForgottenColumn(tx *sql.Tx) error {
|
|
||||||
_, err := tx.Exec(`ALTER TABLE roomserver_membership ADD COLUMN IF NOT EXISTS forgotten BOOLEAN NOT NULL DEFAULT false;`)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute upgrade: %w", err)
|
return fmt.Errorf("failed to execute upgrade: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DownAddForgottenColumn(tx *sql.Tx) error {
|
func DownAddForgottenColumn(ctx context.Context, tx *sql.Tx) error {
|
||||||
_, err := tx.Exec(`ALTER TABLE roomserver_membership DROP COLUMN IF EXISTS forgotten;`)
|
_, err := tx.ExecContext(ctx, `ALTER TABLE roomserver_membership DROP COLUMN IF EXISTS forgotten;`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute downgrade: %w", err)
|
return fmt.Errorf("failed to execute downgrade: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,11 @@
|
||||||
package deltas
|
package deltas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/lib/pq"
|
"github.com/lib/pq"
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
@ -36,48 +36,44 @@ type stateBlockData struct {
|
||||||
EventNIDs types.EventNIDs
|
EventNIDs types.EventNIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadStateBlocksRefactor(m *sqlutil.Migrations) {
|
|
||||||
m.AddMigration(UpStateBlocksRefactor, DownStateBlocksRefactor)
|
|
||||||
}
|
|
||||||
|
|
||||||
// nolint:gocyclo
|
// nolint:gocyclo
|
||||||
func UpStateBlocksRefactor(tx *sql.Tx) error {
|
func UpStateBlocksRefactor(ctx context.Context, tx *sql.Tx) error {
|
||||||
logrus.Warn("Performing state storage upgrade. Please wait, this may take some time!")
|
logrus.Warn("Performing state storage upgrade. Please wait, this may take some time!")
|
||||||
defer logrus.Warn("State storage upgrade complete")
|
defer logrus.Warn("State storage upgrade complete")
|
||||||
|
|
||||||
var snapshotcount int
|
var snapshotcount int
|
||||||
var maxsnapshotid int
|
var maxsnapshotid int
|
||||||
var maxblockid int
|
var maxblockid int
|
||||||
if err := tx.QueryRow(`SELECT COUNT(DISTINCT state_snapshot_nid) FROM roomserver_state_snapshots;`).Scan(&snapshotcount); err != nil {
|
if err := tx.QueryRowContext(ctx, `SELECT COUNT(DISTINCT state_snapshot_nid) FROM roomserver_state_snapshots;`).Scan(&snapshotcount); err != nil {
|
||||||
return fmt.Errorf("tx.QueryRow.Scan (count snapshots): %w", err)
|
return fmt.Errorf("tx.QueryRowContext.Scan (count snapshots): %w", err)
|
||||||
}
|
}
|
||||||
if err := tx.QueryRow(`SELECT COALESCE(MAX(state_snapshot_nid),0) FROM roomserver_state_snapshots;`).Scan(&maxsnapshotid); err != nil {
|
if err := tx.QueryRowContext(ctx, `SELECT COALESCE(MAX(state_snapshot_nid),0) FROM roomserver_state_snapshots;`).Scan(&maxsnapshotid); err != nil {
|
||||||
return fmt.Errorf("tx.QueryRow.Scan (count snapshots): %w", err)
|
return fmt.Errorf("tx.QueryRowContext.Scan (count snapshots): %w", err)
|
||||||
}
|
}
|
||||||
if err := tx.QueryRow(`SELECT COALESCE(MAX(state_block_nid),0) FROM roomserver_state_block;`).Scan(&maxblockid); err != nil {
|
if err := tx.QueryRowContext(ctx, `SELECT COALESCE(MAX(state_block_nid),0) FROM roomserver_state_block;`).Scan(&maxblockid); err != nil {
|
||||||
return fmt.Errorf("tx.QueryRow.Scan (count snapshots): %w", err)
|
return fmt.Errorf("tx.QueryRowContext.Scan (count snapshots): %w", err)
|
||||||
}
|
}
|
||||||
maxsnapshotid++
|
maxsnapshotid++
|
||||||
maxblockid++
|
maxblockid++
|
||||||
|
|
||||||
if _, err := tx.Exec(`ALTER TABLE roomserver_state_block RENAME TO _roomserver_state_block;`); err != nil {
|
if _, err := tx.ExecContext(ctx, `ALTER TABLE roomserver_state_block RENAME TO _roomserver_state_block;`); err != nil {
|
||||||
return fmt.Errorf("tx.Exec: %w", err)
|
return fmt.Errorf("tx.ExecContext: %w", err)
|
||||||
}
|
}
|
||||||
if _, err := tx.Exec(`ALTER TABLE roomserver_state_snapshots RENAME TO _roomserver_state_snapshots;`); err != nil {
|
if _, err := tx.ExecContext(ctx, `ALTER TABLE roomserver_state_snapshots RENAME TO _roomserver_state_snapshots;`); err != nil {
|
||||||
return fmt.Errorf("tx.Exec: %w", err)
|
return fmt.Errorf("tx.ExecContext: %w", err)
|
||||||
}
|
}
|
||||||
// We create new sequences starting with the maximum state snapshot and block NIDs.
|
// We create new sequences starting with the maximum state snapshot and block NIDs.
|
||||||
// This means that all newly created snapshots and blocks by the migration will have
|
// This means that all newly created snapshots and blocks by the migration will have
|
||||||
// NIDs higher than these values, so that when we come to update the references to
|
// NIDs higher than these values, so that when we come to update the references to
|
||||||
// these NIDs using UPDATE statements, we can guarantee we are only ever updating old
|
// these NIDs using UPDATE statements, we can guarantee we are only ever updating old
|
||||||
// values and not accidentally overwriting new ones.
|
// values and not accidentally overwriting new ones.
|
||||||
if _, err := tx.Exec(fmt.Sprintf(`CREATE SEQUENCE roomserver_state_block_nid_sequence START WITH %d;`, maxblockid)); err != nil {
|
if _, err := tx.ExecContext(ctx, fmt.Sprintf(`CREATE SEQUENCE roomserver_state_block_nid_sequence START WITH %d;`, maxblockid)); err != nil {
|
||||||
return fmt.Errorf("tx.Exec: %w", err)
|
return fmt.Errorf("tx.ExecContext: %w", err)
|
||||||
}
|
}
|
||||||
if _, err := tx.Exec(fmt.Sprintf(`CREATE SEQUENCE roomserver_state_snapshot_nid_sequence START WITH %d;`, maxsnapshotid)); err != nil {
|
if _, err := tx.ExecContext(ctx, fmt.Sprintf(`CREATE SEQUENCE roomserver_state_snapshot_nid_sequence START WITH %d;`, maxsnapshotid)); err != nil {
|
||||||
return fmt.Errorf("tx.Exec: %w", err)
|
return fmt.Errorf("tx.ExecContext: %w", err)
|
||||||
}
|
}
|
||||||
_, err := tx.Exec(`
|
_, err := tx.ExecContext(ctx, `
|
||||||
CREATE TABLE IF NOT EXISTS roomserver_state_block (
|
CREATE TABLE IF NOT EXISTS roomserver_state_block (
|
||||||
state_block_nid bigint PRIMARY KEY DEFAULT nextval('roomserver_state_block_nid_sequence'),
|
state_block_nid bigint PRIMARY KEY DEFAULT nextval('roomserver_state_block_nid_sequence'),
|
||||||
state_block_hash BYTEA UNIQUE,
|
state_block_hash BYTEA UNIQUE,
|
||||||
|
|
@ -87,7 +83,7 @@ func UpStateBlocksRefactor(tx *sql.Tx) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("tx.Exec (create blocks table): %w", err)
|
return fmt.Errorf("tx.Exec (create blocks table): %w", err)
|
||||||
}
|
}
|
||||||
_, err = tx.Exec(`
|
_, err = tx.ExecContext(ctx, `
|
||||||
CREATE TABLE IF NOT EXISTS roomserver_state_snapshots (
|
CREATE TABLE IF NOT EXISTS roomserver_state_snapshots (
|
||||||
state_snapshot_nid bigint PRIMARY KEY DEFAULT nextval('roomserver_state_snapshot_nid_sequence'),
|
state_snapshot_nid bigint PRIMARY KEY DEFAULT nextval('roomserver_state_snapshot_nid_sequence'),
|
||||||
state_snapshot_hash BYTEA UNIQUE,
|
state_snapshot_hash BYTEA UNIQUE,
|
||||||
|
|
@ -104,7 +100,7 @@ func UpStateBlocksRefactor(tx *sql.Tx) error {
|
||||||
// in question a state snapshot NID of 0 to indicate 'no snapshot'.
|
// in question a state snapshot NID of 0 to indicate 'no snapshot'.
|
||||||
// If we don't do this, we'll fail the assertions later on which try to ensure we didn't forget
|
// If we don't do this, we'll fail the assertions later on which try to ensure we didn't forget
|
||||||
// any snapshots.
|
// any snapshots.
|
||||||
_, err = tx.Exec(
|
_, err = tx.ExecContext(ctx,
|
||||||
`UPDATE roomserver_events SET state_snapshot_nid = 0 WHERE event_type_nid = $1 AND event_state_key_nid = $2`,
|
`UPDATE roomserver_events SET state_snapshot_nid = 0 WHERE event_type_nid = $1 AND event_state_key_nid = $2`,
|
||||||
types.MRoomCreateNID, types.EmptyStateKeyNID,
|
types.MRoomCreateNID, types.EmptyStateKeyNID,
|
||||||
)
|
)
|
||||||
|
|
@ -115,7 +111,7 @@ func UpStateBlocksRefactor(tx *sql.Tx) error {
|
||||||
batchsize := 100
|
batchsize := 100
|
||||||
for batchoffset := 0; batchoffset < snapshotcount; batchoffset += batchsize {
|
for batchoffset := 0; batchoffset < snapshotcount; batchoffset += batchsize {
|
||||||
var snapshotrows *sql.Rows
|
var snapshotrows *sql.Rows
|
||||||
snapshotrows, err = tx.Query(`
|
snapshotrows, err = tx.QueryContext(ctx, `
|
||||||
SELECT
|
SELECT
|
||||||
state_snapshot_nid,
|
state_snapshot_nid,
|
||||||
room_nid,
|
room_nid,
|
||||||
|
|
@ -146,7 +142,7 @@ func UpStateBlocksRefactor(tx *sql.Tx) error {
|
||||||
state_block_nid;
|
state_block_nid;
|
||||||
`, batchsize, batchoffset)
|
`, batchsize, batchoffset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("tx.Query: %w", err)
|
return fmt.Errorf("tx.QueryContext: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Warnf("Rewriting snapshots %d-%d of %d...", batchoffset, batchoffset+batchsize, snapshotcount)
|
logrus.Warnf("Rewriting snapshots %d-%d of %d...", batchoffset, batchoffset+batchsize, snapshotcount)
|
||||||
|
|
@ -183,7 +179,7 @@ func UpStateBlocksRefactor(tx *sql.Tx) error {
|
||||||
// fill in bad create snapshots
|
// fill in bad create snapshots
|
||||||
for _, s := range badCreateSnapshots {
|
for _, s := range badCreateSnapshots {
|
||||||
var createEventNID types.EventNID
|
var createEventNID types.EventNID
|
||||||
err = tx.QueryRow(
|
err = tx.QueryRowContext(ctx,
|
||||||
`SELECT event_nid FROM roomserver_events WHERE state_snapshot_nid = $1 AND event_type_nid = 1`, s.StateSnapshotNID,
|
`SELECT event_nid FROM roomserver_events WHERE state_snapshot_nid = $1 AND event_type_nid = 1`, s.StateSnapshotNID,
|
||||||
).Scan(&createEventNID)
|
).Scan(&createEventNID)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
|
|
@ -208,7 +204,7 @@ func UpStateBlocksRefactor(tx *sql.Tx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var blocknid types.StateBlockNID
|
var blocknid types.StateBlockNID
|
||||||
err = tx.QueryRow(`
|
err = tx.QueryRowContext(ctx, `
|
||||||
INSERT INTO roomserver_state_block (state_block_hash, event_nids)
|
INSERT INTO roomserver_state_block (state_block_hash, event_nids)
|
||||||
VALUES ($1, $2)
|
VALUES ($1, $2)
|
||||||
ON CONFLICT (state_block_hash) DO UPDATE SET event_nids=$2
|
ON CONFLICT (state_block_hash) DO UPDATE SET event_nids=$2
|
||||||
|
|
@ -227,7 +223,7 @@ func UpStateBlocksRefactor(tx *sql.Tx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var newNID types.StateSnapshotNID
|
var newNID types.StateSnapshotNID
|
||||||
err = tx.QueryRow(`
|
err = tx.QueryRowContext(ctx, `
|
||||||
INSERT INTO roomserver_state_snapshots (state_snapshot_hash, room_nid, state_block_nids)
|
INSERT INTO roomserver_state_snapshots (state_snapshot_hash, room_nid, state_block_nids)
|
||||||
VALUES ($1, $2, $3)
|
VALUES ($1, $2, $3)
|
||||||
ON CONFLICT (state_snapshot_hash) DO UPDATE SET room_nid=$2
|
ON CONFLICT (state_snapshot_hash) DO UPDATE SET room_nid=$2
|
||||||
|
|
@ -237,12 +233,12 @@ func UpStateBlocksRefactor(tx *sql.Tx) error {
|
||||||
return fmt.Errorf("tx.QueryRow.Scan (insert new snapshot): %w", err)
|
return fmt.Errorf("tx.QueryRow.Scan (insert new snapshot): %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = tx.Exec(`UPDATE roomserver_events SET state_snapshot_nid=$1 WHERE state_snapshot_nid=$2 AND state_snapshot_nid<$3`, newNID, snapshotdata.StateSnapshotNID, maxsnapshotid); err != nil {
|
if _, err = tx.ExecContext(ctx, `UPDATE roomserver_events SET state_snapshot_nid=$1 WHERE state_snapshot_nid=$2 AND state_snapshot_nid<$3`, newNID, snapshotdata.StateSnapshotNID, maxsnapshotid); err != nil {
|
||||||
return fmt.Errorf("tx.Exec (update events): %w", err)
|
return fmt.Errorf("tx.ExecContext (update events): %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = tx.Exec(`UPDATE roomserver_rooms SET state_snapshot_nid=$1 WHERE state_snapshot_nid=$2 AND state_snapshot_nid<$3`, newNID, snapshotdata.StateSnapshotNID, maxsnapshotid); err != nil {
|
if _, err = tx.ExecContext(ctx, `UPDATE roomserver_rooms SET state_snapshot_nid=$1 WHERE state_snapshot_nid=$2 AND state_snapshot_nid<$3`, newNID, snapshotdata.StateSnapshotNID, maxsnapshotid); err != nil {
|
||||||
return fmt.Errorf("tx.Exec (update rooms): %w", err)
|
return fmt.Errorf("tx.ExecContext (update rooms): %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -252,13 +248,13 @@ func UpStateBlocksRefactor(tx *sql.Tx) error {
|
||||||
// in roomserver_state_snapshots
|
// in roomserver_state_snapshots
|
||||||
var count int64
|
var count int64
|
||||||
|
|
||||||
if err = tx.QueryRow(`SELECT COUNT(*) FROM roomserver_events WHERE state_snapshot_nid < $1 AND state_snapshot_nid != 0`, maxsnapshotid).Scan(&count); err != nil {
|
if err = tx.QueryRowContext(ctx, `SELECT COUNT(*) FROM roomserver_events WHERE state_snapshot_nid < $1 AND state_snapshot_nid != 0`, maxsnapshotid).Scan(&count); err != nil {
|
||||||
return fmt.Errorf("assertion query failed: %s", err)
|
return fmt.Errorf("assertion query failed: %s", err)
|
||||||
}
|
}
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
var res sql.Result
|
var res sql.Result
|
||||||
var c int64
|
var c int64
|
||||||
res, err = tx.Exec(`UPDATE roomserver_events SET state_snapshot_nid = 0 WHERE state_snapshot_nid < $1 AND state_snapshot_nid != 0`, maxsnapshotid)
|
res, err = tx.ExecContext(ctx, `UPDATE roomserver_events SET state_snapshot_nid = 0 WHERE state_snapshot_nid < $1 AND state_snapshot_nid != 0`, maxsnapshotid)
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return fmt.Errorf("failed to reset invalid state snapshots: %w", err)
|
return fmt.Errorf("failed to reset invalid state snapshots: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -268,13 +264,13 @@ func UpStateBlocksRefactor(tx *sql.Tx) error {
|
||||||
return fmt.Errorf("expected to reset %d event(s) but only updated %d event(s)", count, c)
|
return fmt.Errorf("expected to reset %d event(s) but only updated %d event(s)", count, c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = tx.QueryRow(`SELECT COUNT(*) FROM roomserver_rooms WHERE state_snapshot_nid < $1 AND state_snapshot_nid != 0`, maxsnapshotid).Scan(&count); err != nil {
|
if err = tx.QueryRowContext(ctx, `SELECT COUNT(*) FROM roomserver_rooms WHERE state_snapshot_nid < $1 AND state_snapshot_nid != 0`, maxsnapshotid).Scan(&count); err != nil {
|
||||||
return fmt.Errorf("assertion query failed: %s", err)
|
return fmt.Errorf("assertion query failed: %s", err)
|
||||||
}
|
}
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
var debugRoomID string
|
var debugRoomID string
|
||||||
var debugSnapNID, debugLastEventNID int64
|
var debugSnapNID, debugLastEventNID int64
|
||||||
err = tx.QueryRow(
|
err = tx.QueryRowContext(ctx,
|
||||||
`SELECT room_id, state_snapshot_nid, last_event_sent_nid FROM roomserver_rooms WHERE state_snapshot_nid < $1 AND state_snapshot_nid != 0`, maxsnapshotid,
|
`SELECT room_id, state_snapshot_nid, last_event_sent_nid FROM roomserver_rooms WHERE state_snapshot_nid < $1 AND state_snapshot_nid != 0`, maxsnapshotid,
|
||||||
).Scan(&debugRoomID, &debugSnapNID, &debugLastEventNID)
|
).Scan(&debugRoomID, &debugSnapNID, &debugLastEventNID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -291,13 +287,13 @@ func UpStateBlocksRefactor(tx *sql.Tx) error {
|
||||||
return fmt.Errorf("%d rooms exist in roomserver_rooms which have not been converted to a new state_snapshot_nid; this is a bug, please report", count)
|
return fmt.Errorf("%d rooms exist in roomserver_rooms which have not been converted to a new state_snapshot_nid; this is a bug, please report", count)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = tx.Exec(`
|
if _, err = tx.ExecContext(ctx, `
|
||||||
DROP TABLE _roomserver_state_snapshots;
|
DROP TABLE _roomserver_state_snapshots;
|
||||||
DROP SEQUENCE roomserver_state_snapshot_nid_seq;
|
DROP SEQUENCE roomserver_state_snapshot_nid_seq;
|
||||||
`); err != nil {
|
`); err != nil {
|
||||||
return fmt.Errorf("tx.Exec (delete old snapshot table): %w", err)
|
return fmt.Errorf("tx.Exec (delete old snapshot table): %w", err)
|
||||||
}
|
}
|
||||||
if _, err = tx.Exec(`
|
if _, err = tx.ExecContext(ctx, `
|
||||||
DROP TABLE _roomserver_state_block;
|
DROP TABLE _roomserver_state_block;
|
||||||
DROP SEQUENCE roomserver_state_block_nid_seq;
|
DROP SEQUENCE roomserver_state_block_nid_seq;
|
||||||
`); err != nil {
|
`); err != nil {
|
||||||
|
|
@ -307,6 +303,6 @@ func UpStateBlocksRefactor(tx *sql.Tx) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DownStateBlocksRefactor(tx *sql.Tx) error {
|
func DownStateBlocksRefactor(ctx context.Context, tx *sql.Tx) error {
|
||||||
panic("Downgrading state storage is not supported")
|
panic("Downgrading state storage is not supported")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/lib/pq"
|
"github.com/lib/pq"
|
||||||
"github.com/matrix-org/dendrite/internal"
|
"github.com/matrix-org/dendrite/internal"
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/roomserver/storage/postgres/deltas"
|
||||||
"github.com/matrix-org/dendrite/roomserver/storage/tables"
|
"github.com/matrix-org/dendrite/roomserver/storage/tables"
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
@ -65,12 +66,18 @@ CREATE TABLE IF NOT EXISTS roomserver_membership (
|
||||||
);
|
);
|
||||||
`
|
`
|
||||||
|
|
||||||
var selectJoinedUsersSetForRoomsSQL = "" +
|
var selectJoinedUsersSetForRoomsAndUserSQL = "" +
|
||||||
"SELECT target_nid, COUNT(room_nid) FROM roomserver_membership" +
|
"SELECT target_nid, COUNT(room_nid) FROM roomserver_membership" +
|
||||||
" WHERE room_nid = ANY($1) AND target_nid = ANY($2) AND" +
|
" WHERE room_nid = ANY($1) AND target_nid = ANY($2) AND" +
|
||||||
" membership_nid = " + fmt.Sprintf("%d", tables.MembershipStateJoin) + " and forgotten = false" +
|
" membership_nid = " + fmt.Sprintf("%d", tables.MembershipStateJoin) + " and forgotten = false" +
|
||||||
" GROUP BY target_nid"
|
" GROUP BY target_nid"
|
||||||
|
|
||||||
|
var selectJoinedUsersSetForRoomsSQL = "" +
|
||||||
|
"SELECT target_nid, COUNT(room_nid) FROM roomserver_membership" +
|
||||||
|
" WHERE room_nid = ANY($1) AND" +
|
||||||
|
" membership_nid = " + fmt.Sprintf("%d", tables.MembershipStateJoin) + " and forgotten = false" +
|
||||||
|
" GROUP BY target_nid"
|
||||||
|
|
||||||
// Insert a row in to membership table so that it can be locked by the
|
// Insert a row in to membership table so that it can be locked by the
|
||||||
// SELECT FOR UPDATE
|
// SELECT FOR UPDATE
|
||||||
const insertMembershipSQL = "" +
|
const insertMembershipSQL = "" +
|
||||||
|
|
@ -80,24 +87,24 @@ const insertMembershipSQL = "" +
|
||||||
|
|
||||||
const selectMembershipFromRoomAndTargetSQL = "" +
|
const selectMembershipFromRoomAndTargetSQL = "" +
|
||||||
"SELECT membership_nid, event_nid, forgotten FROM roomserver_membership" +
|
"SELECT membership_nid, event_nid, forgotten FROM roomserver_membership" +
|
||||||
" WHERE room_nid = $1 AND target_nid = $2"
|
" WHERE room_nid = $1 AND event_nid != 0 AND target_nid = $2"
|
||||||
|
|
||||||
const selectMembershipsFromRoomAndMembershipSQL = "" +
|
const selectMembershipsFromRoomAndMembershipSQL = "" +
|
||||||
"SELECT event_nid FROM roomserver_membership" +
|
"SELECT event_nid FROM roomserver_membership" +
|
||||||
" WHERE room_nid = $1 AND membership_nid = $2 and forgotten = false"
|
" WHERE room_nid = $1 AND event_nid != 0 AND membership_nid = $2 and forgotten = false"
|
||||||
|
|
||||||
const selectLocalMembershipsFromRoomAndMembershipSQL = "" +
|
const selectLocalMembershipsFromRoomAndMembershipSQL = "" +
|
||||||
"SELECT event_nid FROM roomserver_membership" +
|
"SELECT event_nid FROM roomserver_membership" +
|
||||||
" WHERE room_nid = $1 AND membership_nid = $2" +
|
" WHERE room_nid = $1 AND event_nid != 0 AND membership_nid = $2" +
|
||||||
" AND target_local = true and forgotten = false"
|
" AND target_local = true and forgotten = false"
|
||||||
|
|
||||||
const selectMembershipsFromRoomSQL = "" +
|
const selectMembershipsFromRoomSQL = "" +
|
||||||
"SELECT event_nid FROM roomserver_membership" +
|
"SELECT event_nid FROM roomserver_membership" +
|
||||||
" WHERE room_nid = $1 and forgotten = false"
|
" WHERE room_nid = $1 AND event_nid != 0 and forgotten = false"
|
||||||
|
|
||||||
const selectLocalMembershipsFromRoomSQL = "" +
|
const selectLocalMembershipsFromRoomSQL = "" +
|
||||||
"SELECT event_nid FROM roomserver_membership" +
|
"SELECT event_nid FROM roomserver_membership" +
|
||||||
" WHERE room_nid = $1" +
|
" WHERE room_nid = $1 AND event_nid != 0" +
|
||||||
" AND target_local = true and forgotten = false"
|
" AND target_local = true and forgotten = false"
|
||||||
|
|
||||||
const selectMembershipForUpdateSQL = "" +
|
const selectMembershipForUpdateSQL = "" +
|
||||||
|
|
@ -112,6 +119,9 @@ const updateMembershipForgetRoom = "" +
|
||||||
"UPDATE roomserver_membership SET forgotten = $3" +
|
"UPDATE roomserver_membership SET forgotten = $3" +
|
||||||
" WHERE room_nid = $1 AND target_nid = $2"
|
" WHERE room_nid = $1 AND target_nid = $2"
|
||||||
|
|
||||||
|
const deleteMembershipSQL = "" +
|
||||||
|
"DELETE FROM roomserver_membership WHERE room_nid = $1 AND target_nid = $2"
|
||||||
|
|
||||||
const selectRoomsWithMembershipSQL = "" +
|
const selectRoomsWithMembershipSQL = "" +
|
||||||
"SELECT room_nid FROM roomserver_membership WHERE membership_nid = $1 AND target_nid = $2 and forgotten = false"
|
"SELECT room_nid FROM roomserver_membership WHERE membership_nid = $1 AND target_nid = $2 and forgotten = false"
|
||||||
|
|
||||||
|
|
@ -153,16 +163,26 @@ type membershipStatements struct {
|
||||||
selectLocalMembershipsFromRoomStmt *sql.Stmt
|
selectLocalMembershipsFromRoomStmt *sql.Stmt
|
||||||
updateMembershipStmt *sql.Stmt
|
updateMembershipStmt *sql.Stmt
|
||||||
selectRoomsWithMembershipStmt *sql.Stmt
|
selectRoomsWithMembershipStmt *sql.Stmt
|
||||||
|
selectJoinedUsersSetForRoomsAndUserStmt *sql.Stmt
|
||||||
selectJoinedUsersSetForRoomsStmt *sql.Stmt
|
selectJoinedUsersSetForRoomsStmt *sql.Stmt
|
||||||
selectKnownUsersStmt *sql.Stmt
|
selectKnownUsersStmt *sql.Stmt
|
||||||
updateMembershipForgetRoomStmt *sql.Stmt
|
updateMembershipForgetRoomStmt *sql.Stmt
|
||||||
selectLocalServerInRoomStmt *sql.Stmt
|
selectLocalServerInRoomStmt *sql.Stmt
|
||||||
selectServerInRoomStmt *sql.Stmt
|
selectServerInRoomStmt *sql.Stmt
|
||||||
|
deleteMembershipStmt *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateMembershipTable(db *sql.DB) error {
|
func CreateMembershipTable(db *sql.DB) error {
|
||||||
_, err := db.Exec(membershipSchema)
|
_, err := db.Exec(membershipSchema)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m := sqlutil.NewMigrator(db)
|
||||||
|
m.AddMigrations(sqlutil.Migration{
|
||||||
|
Version: "roomserver: add forgotten column",
|
||||||
|
Up: deltas.UpAddForgottenColumn,
|
||||||
|
})
|
||||||
|
return m.Up(context.Background())
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrepareMembershipTable(db *sql.DB) (tables.Membership, error) {
|
func PrepareMembershipTable(db *sql.DB) (tables.Membership, error) {
|
||||||
|
|
@ -178,11 +198,13 @@ func PrepareMembershipTable(db *sql.DB) (tables.Membership, error) {
|
||||||
{&s.selectLocalMembershipsFromRoomStmt, selectLocalMembershipsFromRoomSQL},
|
{&s.selectLocalMembershipsFromRoomStmt, selectLocalMembershipsFromRoomSQL},
|
||||||
{&s.updateMembershipStmt, updateMembershipSQL},
|
{&s.updateMembershipStmt, updateMembershipSQL},
|
||||||
{&s.selectRoomsWithMembershipStmt, selectRoomsWithMembershipSQL},
|
{&s.selectRoomsWithMembershipStmt, selectRoomsWithMembershipSQL},
|
||||||
|
{&s.selectJoinedUsersSetForRoomsAndUserStmt, selectJoinedUsersSetForRoomsAndUserSQL},
|
||||||
{&s.selectJoinedUsersSetForRoomsStmt, selectJoinedUsersSetForRoomsSQL},
|
{&s.selectJoinedUsersSetForRoomsStmt, selectJoinedUsersSetForRoomsSQL},
|
||||||
{&s.selectKnownUsersStmt, selectKnownUsersSQL},
|
{&s.selectKnownUsersStmt, selectKnownUsersSQL},
|
||||||
{&s.updateMembershipForgetRoomStmt, updateMembershipForgetRoom},
|
{&s.updateMembershipForgetRoomStmt, updateMembershipForgetRoom},
|
||||||
{&s.selectLocalServerInRoomStmt, selectLocalServerInRoomSQL},
|
{&s.selectLocalServerInRoomStmt, selectLocalServerInRoomSQL},
|
||||||
{&s.selectServerInRoomStmt, selectServerInRoomSQL},
|
{&s.selectServerInRoomStmt, selectServerInRoomSQL},
|
||||||
|
{&s.deleteMembershipStmt, deleteMembershipSQL},
|
||||||
}.Prepare(db)
|
}.Prepare(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -313,8 +335,18 @@ func (s *membershipStatements) SelectJoinedUsersSetForRooms(
|
||||||
roomNIDs []types.RoomNID,
|
roomNIDs []types.RoomNID,
|
||||||
userNIDs []types.EventStateKeyNID,
|
userNIDs []types.EventStateKeyNID,
|
||||||
) (map[types.EventStateKeyNID]int, error) {
|
) (map[types.EventStateKeyNID]int, error) {
|
||||||
|
var (
|
||||||
|
rows *sql.Rows
|
||||||
|
err error
|
||||||
|
)
|
||||||
stmt := sqlutil.TxStmt(txn, s.selectJoinedUsersSetForRoomsStmt)
|
stmt := sqlutil.TxStmt(txn, s.selectJoinedUsersSetForRoomsStmt)
|
||||||
rows, err := stmt.QueryContext(ctx, pq.Array(roomNIDs), pq.Array(userNIDs))
|
if len(userNIDs) > 0 {
|
||||||
|
stmt = sqlutil.TxStmt(txn, s.selectJoinedUsersSetForRoomsAndUserStmt)
|
||||||
|
rows, err = stmt.QueryContext(ctx, pq.Array(roomNIDs), pq.Array(userNIDs))
|
||||||
|
} else {
|
||||||
|
rows, err = stmt.QueryContext(ctx, pq.Array(roomNIDs))
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -394,3 +426,13 @@ func (s *membershipStatements) SelectServerInRoom(
|
||||||
}
|
}
|
||||||
return roomNID == nid, nil
|
return roomNID == nid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *membershipStatements) DeleteMembership(
|
||||||
|
ctx context.Context, txn *sql.Tx,
|
||||||
|
roomNID types.RoomNID, targetUserNID types.EventStateKeyNID,
|
||||||
|
) error {
|
||||||
|
_, err := sqlutil.TxStmt(txn, s.deleteMembershipStmt).ExecContext(
|
||||||
|
ctx, roomNID, targetUserNID,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue