chore: seed migration objects batch 18
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 0 B After Width: | Height: | Size: 169 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 0 B After Width: | Height: | Size: 932 KiB |
@@ -1,110 +1,215 @@
|
|||||||
|
cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs=
|
||||||
cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||||
|
cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=
|
||||||
cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
|
cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
|
||||||
|
cloud.google.com/go/auth v0.20.0 h1:kXTssoVb4azsVDoUiF8KvxAqrsQcQtB53DcSgta74CA=
|
||||||
cloud.google.com/go/auth v0.20.0/go.mod h1:942/yi/itH1SsmpyrbnTMDgGfdy2BUqIKyd0cyYLc5Q=
|
cloud.google.com/go/auth v0.20.0/go.mod h1:942/yi/itH1SsmpyrbnTMDgGfdy2BUqIKyd0cyYLc5Q=
|
||||||
|
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||||
|
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
|
||||||
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
||||||
|
cloud.google.com/go/firestore v1.22.0 h1:avooeboIq37vKXobrbPUFhFBxS/c3FqmWoX0xs8dO6E=
|
||||||
cloud.google.com/go/firestore v1.22.0/go.mod h1:PaM4i7i7ruALSKmlpHXXZaPObcZw0W7ie5UOPr72iTU=
|
cloud.google.com/go/firestore v1.22.0/go.mod h1:PaM4i7i7ruALSKmlpHXXZaPObcZw0W7ie5UOPr72iTU=
|
||||||
|
cloud.google.com/go/iam v1.11.0 h1:KieQ9Pb+LLPak1O3Rv3GgCxhnmkYf7Xyh0P5HfF1jFM=
|
||||||
cloud.google.com/go/iam v1.11.0/go.mod h1:KP+nKGugNJW4LcLx1uEZcq1ok5sQHFaQehQNl4QDgV4=
|
cloud.google.com/go/iam v1.11.0/go.mod h1:KP+nKGugNJW4LcLx1uEZcq1ok5sQHFaQehQNl4QDgV4=
|
||||||
|
cloud.google.com/go/logging v1.18.0 h1:KhzZq+1cSkPH9YUaKLLhLtQxIHitVayBmk0sGfoM9+k=
|
||||||
|
cloud.google.com/go/logging v1.18.0/go.mod h1:ZGKnpBaURITh+g/uom2VhbiFoFWvejcrHPDhxFtU/gI=
|
||||||
|
cloud.google.com/go/longrunning v1.1.0 h1:qJ0R0IA8ONaRCNWTRPAS0iAmt1bj3TVgJ40z7ZGRslE=
|
||||||
cloud.google.com/go/longrunning v1.1.0/go.mod h1:tH+A/6UvNypiPJWAQaKCsh+xiGbB23wUO8egwUXlD2E=
|
cloud.google.com/go/longrunning v1.1.0/go.mod h1:tH+A/6UvNypiPJWAQaKCsh+xiGbB23wUO8egwUXlD2E=
|
||||||
|
cloud.google.com/go/monitoring v1.29.0 h1:AHhDsFaSax1/4k+qlIDX/SDGe6hggnfXJ9dkgD9qBPY=
|
||||||
cloud.google.com/go/monitoring v1.29.0/go.mod h1:72NOVjJXHY/HBfoLT0+qlCZBT059+9VXLeAnL2PeeVM=
|
cloud.google.com/go/monitoring v1.29.0/go.mod h1:72NOVjJXHY/HBfoLT0+qlCZBT059+9VXLeAnL2PeeVM=
|
||||||
|
cloud.google.com/go/storage v1.63.0 h1:hvXF2xfg9I32bjujggxgkEZn/Ej6sJ9pieFgeueBLrQ=
|
||||||
cloud.google.com/go/storage v1.63.0/go.mod h1:tirWVptrFNo5GEX2DQ47JooF7yaweJdAJ1hYAVMvKzE=
|
cloud.google.com/go/storage v1.63.0/go.mod h1:tirWVptrFNo5GEX2DQ47JooF7yaweJdAJ1hYAVMvKzE=
|
||||||
|
cloud.google.com/go/trace v1.16.0 h1:GmQovzFc5F0CNfl0VLgL64aoTtu7xsM0YajW2GlG9+E=
|
||||||
|
cloud.google.com/go/trace v1.16.0/go.mod h1:r+bdAn16dKLSV1G2D5v3e58IlQlizfxWrUfjx7kM7X0=
|
||||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
|
filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
|
||||||
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
|
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
|
||||||
|
firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4=
|
||||||
firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs=
|
firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.33.0 h1:l7+6kwRMJNwdCvYdDl7Eax+wzEYHSnNY7zrrfbhDdTA=
|
||||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.33.0/go.mod h1:pJTkW8hEUIIi3Pf65lPZOnn4Y81yCllX6IWk2jNXdkM=
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.33.0/go.mod h1:pJTkW8hEUIIi3Pf65lPZOnn4Y81yCllX6IWk2jNXdkM=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0 h1:jLdiS1vO+XJFyDSWRHBx56r4s/NNtcl5J6KyCcWUX/w=
|
||||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0/go.mod h1:8lmpHY+1VRoteiOwyrQMDt1YGXOrFKCz+1wJW7n3ODY=
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0/go.mod h1:8lmpHY+1VRoteiOwyrQMDt1YGXOrFKCz+1wJW7n3ODY=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.57.0 h1:cSjUzZ7KU8hicTgzaSv9NmSyM9fTVK3y5lsBUl3wOis=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.57.0/go.mod h1:dzcEjy1WJ0Q4u9twNR3LcLhNoYMRCrMCMafpxa0TjPQ=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0 h1:RoO5+d7uCmDqovLrHCr2/BuViUXvdcrNxyNM1pN9dDQ=
|
||||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0/go.mod h1:YqwkQPrWSC7+byyc1VlKbWLBF5JsW5IoL6xUkemYSXk=
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0/go.mod h1:YqwkQPrWSC7+byyc1VlKbWLBF5JsW5IoL6xUkemYSXk=
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.42.1 h1:9eOTgu1z/dVtYpNZ3/8/XbbaX0x/BqE3HUzAzs6K0ek=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.42.1/go.mod h1:5pKeft2eJj+gElQ38Jqg4ibCqh+/AK33/0X3hip7IjM=
|
github.com/aws/aws-sdk-go-v2 v1.42.1/go.mod h1:5pKeft2eJj+gElQ38Jqg4ibCqh+/AK33/0X3hip7IjM=
|
||||||
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.14 h1:3IZY0XAJquT3aHzbkHfPzy4ACPcEjVG0x87KOwtpqGY=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.14/go.mod h1:zwM6veDkhGgQFqkBy+uT28AAYpLu+uFMlPl+rCg/73E=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.14/go.mod h1:zwM6veDkhGgQFqkBy+uT28AAYpLu+uFMlPl+rCg/73E=
|
||||||
|
github.com/aws/aws-sdk-go-v2/config v1.32.27 h1:SJwJ9Q4kM7v5QVSYYyXj3znRr6lNyZEhSgAXmXXcVbI=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.32.27/go.mod h1:uBfrzTRedDmB2u+b6+UlaKJy2O6VSH5un2jP24t/KvQ=
|
github.com/aws/aws-sdk-go-v2/config v1.32.27/go.mod h1:uBfrzTRedDmB2u+b6+UlaKJy2O6VSH5un2jP24t/KvQ=
|
||||||
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.26 h1:Si8kk1kyJnuJWCEgiwpBtTdtgSdR7i611596NnC0YIQ=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.26/go.mod h1:lBckz+W9SAdNtSDw3pYgQUJDJFcBBWry0GSzw+bK0TY=
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.26/go.mod h1:lBckz+W9SAdNtSDw3pYgQUJDJFcBBWry0GSzw+bK0TY=
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.30 h1:/hi1JADLEW9YYryEz1w4GQu0EtP23pP553Cf9KgsDV4=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.30/go.mod h1:/3AOgy4K17Dm4ucMZVC/MJkzy5kmfKUcINRHZyo0koQ=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.30/go.mod h1:/3AOgy4K17Dm4ucMZVC/MJkzy5kmfKUcINRHZyo0koQ=
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/s3/transfermanager v0.2.13 h1:zHi0z+ZT207/QPyaCmTr4JksQ0Ty0DM+WXW0xsfckXQ=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/transfermanager v0.2.13/go.mod h1:ycxBs1ztF7RbxNWiJoIegPCvsfuO7dCvtyyloQvRgNs=
|
github.com/aws/aws-sdk-go-v2/feature/s3/transfermanager v0.2.13/go.mod h1:ycxBs1ztF7RbxNWiJoIegPCvsfuO7dCvtyyloQvRgNs=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.30 h1:xM/Is9cKMHa8Jj8zkvWhvrFkZsXJV9E+BB4g0HW0duQ=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.30/go.mod h1:WueJeNDZvK1fMYEWJIkcivBfEzUkTpBhzlrUKKY8EuA=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.30/go.mod h1:WueJeNDZvK1fMYEWJIkcivBfEzUkTpBhzlrUKKY8EuA=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30 h1:jn46zC9LdsVR/ZpMIJqMqb8hHv31BlLx3ulVqNspUOk=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30/go.mod h1:1hTMsAgbdS/AtUi4bw8+gUuh1pceo+eXRLfpSuSQj3M=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30/go.mod h1:1hTMsAgbdS/AtUi4bw8+gUuh1pceo+eXRLfpSuSQj3M=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.31 h1:3GUprIsfmGcC5SACIyB0e7E0BM1O1b3Erl5CePYIAeQ=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.31/go.mod h1:7PuV1yl5e2xnUbm+RqvVg5i2iBM8EyijZNoI9wsOoOc=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.31/go.mod h1:7PuV1yl5e2xnUbm+RqvVg5i2iBM8EyijZNoI9wsOoOc=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13 h1:mbRIur/BiHK6SKPjoBIXSE/hJ6g6JGRLuxQy1jGjlN4=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13/go.mod h1:ITg9em2KbJx1s0y4aqRX5OYWG6HBZ5TVR//OdpEZ2CQ=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13/go.mod h1:ITg9em2KbJx1s0y4aqRX5OYWG6HBZ5TVR//OdpEZ2CQ=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.23 h1:9Fjh6fi/U5JEStVZijmaMpUwE/gvBJj7x2B/PjbO9To=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.23/go.mod h1:iMoT2f1tClxrWAAnKCXjZQ6LOmfLrMG14wmnWpM+F14=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.23/go.mod h1:iMoT2f1tClxrWAAnKCXjZQ6LOmfLrMG14wmnWpM+F14=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30 h1:/Z5jmNrKsSD7EmDjzAPsm/3L9IuOkzaynklJZ1qX7S4=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30/go.mod h1:lEzEZnOosE7zi8Z6royW1cFJTD9fpab4Ul1SBrllewk=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30/go.mod h1:lEzEZnOosE7zi8Z6royW1cFJTD9fpab4Ul1SBrllewk=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.31 h1:uao4A3QZ5UmB326V6KF+qRpv9Tjz7IlnlnTbbANntlU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.31/go.mod h1:I/1+z0VwL1GhQyLgkoHDlygpUZ+iTAwOQ/NsftiUL2I=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.31/go.mod h1:I/1+z0VwL1GhQyLgkoHDlygpUZ+iTAwOQ/NsftiUL2I=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.104.2 h1:bAY6O/TDv1HQnvylh9E247IyIKsUWUt2G965S7qX110=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.104.2/go.mod h1:zdmCoFO/dSI7GlrwsPqFJI+WlFnSU4Tc8TJnlXrM1Do=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.104.2/go.mod h1:zdmCoFO/dSI7GlrwsPqFJI+WlFnSU4Tc8TJnlXrM1Do=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/signin v1.2.2 h1:69JEZSDTQ+UNbTWQJCZMmbpQb5sfc79KUt0O7Pyfjmo=
|
||||||
github.com/aws/aws-sdk-go-v2/service/signin v1.2.2/go.mod h1:mxC0nT/C8wMMS97DemZPzvUZxvIt+2Iq+eS3JdFZGgg=
|
github.com/aws/aws-sdk-go-v2/service/signin v1.2.2/go.mod h1:mxC0nT/C8wMMS97DemZPzvUZxvIt+2Iq+eS3JdFZGgg=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.31.5 h1:xlK3Tdc8FO7Tq1k0+hL+otF33glj+dE+qeM5iINiDvU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.31.5/go.mod h1:u8af9Nqkmqnr96f7v9nHqzZT9XBwbXEkTiqT4ROuJSE=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.31.5/go.mod h1:u8af9Nqkmqnr96f7v9nHqzZT9XBwbXEkTiqT4ROuJSE=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.8 h1:yX1IbiBfC7SdEgDwIGnRaZyPPDRbQPDOJxl8102PcGk=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.8/go.mod h1:DMPWJBjYs6+3+f/qhBFEFPPlQ6NlhWjai3dJNvipJ84=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.8/go.mod h1:DMPWJBjYs6+3+f/qhBFEFPPlQ6NlhWjai3dJNvipJ84=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.43.5 h1:T3ANO8QWDbzQD8f4+UaX+fvJlyGnOFMKLbW+NGBHg04=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.43.5/go.mod h1:9gdl4RrflIdpDb2TlXshWgR1F9TeCkvqDx77Vpr4Z/Q=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.43.5/go.mod h1:9gdl4RrflIdpDb2TlXshWgR1F9TeCkvqDx77Vpr4Z/Q=
|
||||||
|
github.com/aws/smithy-go v1.27.3 h1:F3Zb497UhhskkfpJmfkXswyo+t0sh9OTBnIHjogWbVY=
|
||||||
github.com/aws/smithy-go v1.27.3/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
|
github.com/aws/smithy-go v1.27.3/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0=
|
||||||
github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw=
|
github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw=
|
||||||
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik=
|
||||||
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4=
|
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4=
|
||||||
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/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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU=
|
||||||
|
github.com/envoyproxy/go-control-plane/envoy v1.37.0 h1:u3riX6BoYRfF4Dr7dwSOroNfdSbEPe9Yyl09/B6wBrQ=
|
||||||
github.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A=
|
github.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A=
|
||||||
|
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=
|
||||||
|
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds=
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0=
|
github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0=
|
||||||
|
github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc=
|
||||||
github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
|
github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
|
||||||
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/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA=
|
||||||
github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
|
github.com/go-sql-driver/mysql v1.10.0 h1:Q+1LV8DkHJvSYAdR83XzuhDaTykuDx0l6fkXxoWCWfw=
|
||||||
github.com/go-sql-driver/mysql v1.10.0/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk=
|
github.com/go-sql-driver/mysql v1.10.0/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||||
|
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
|
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
||||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=
|
||||||
|
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
|
||||||
|
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.3.17 h1:73NfMHdiqo9JFU9+7a5ExpVa10/R29pXfZIaW559nrg=
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.17/go.mod h1:rSEsBUemEBZEexP2y6jPp16LUmUbjmSbcPMQizR0o4k=
|
github.com/googleapis/enterprise-certificate-proxy v0.3.17/go.mod h1:rSEsBUemEBZEexP2y6jPp16LUmUbjmSbcPMQizR0o4k=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4=
|
||||||
github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY=
|
github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY=
|
||||||
|
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
|
||||||
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
|
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
|
||||||
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||||
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/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0=
|
||||||
github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
|
github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
|
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
||||||
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
||||||
|
github.com/klauspost/compress v1.19.0 h1:sXLILfc9jV2QYWkzFOPWStmcUVH2RHEB1JCdY2oVvCQ=
|
||||||
github.com/klauspost/compress v1.19.0/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
github.com/klauspost/compress v1.19.0/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||||
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.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/localtunnel/go-localtunnel v0.0.0-20170326223115-8a804488f275 h1:IZycmTpoUtQK3PD60UYBwjaCUHUP7cML494ao9/O8+Q=
|
||||||
|
github.com/localtunnel/go-localtunnel v0.0.0-20170326223115-8a804488f275/go.mod h1:zt6UU74K6Z6oMOYJbJzYpYucqdcQwSMPBEdSvGiaUMw=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
|
github.com/montanaflynn/stats v0.9.0 h1:tsBJ0RXwph9BmAuFoCmqGv6e8xa0MENQ8m0ptKq29mQ=
|
||||||
github.com/montanaflynn/stats v0.9.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
github.com/montanaflynn/stats v0.9.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
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/nyaruka/phonenumbers v1.8.0 h1:TrXNJmbwcAHajzDqin3mLWw57vqLUA6ZjVdeNds0heQ=
|
||||||
github.com/nyaruka/phonenumbers v1.8.0/go.mod h1:fsKPJ70O9JetEA4ggnJadYTFWwtGPvu/lETTXNXq6Cs=
|
github.com/nyaruka/phonenumbers v1.8.0/go.mod h1:fsKPJ70O9JetEA4ggnJadYTFWwtGPvu/lETTXNXq6Cs=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
|
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||||
|
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/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||||
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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||||
|
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||||
|
github.com/prometheus/common v0.69.0 h1:OA85nJQS/T/MaYh/Q2CcgDKSGWqNIgrBDvDH85CuiNk=
|
||||||
github.com/prometheus/common v0.69.0/go.mod h1:ZzL3f6u94qUxh9p+tJTrF+FvBS1XXbbRAZCQkytAL0Y=
|
github.com/prometheus/common v0.69.0/go.mod h1:ZzL3f6u94qUxh9p+tJTrF+FvBS1XXbbRAZCQkytAL0Y=
|
||||||
|
github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI=
|
||||||
github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY=
|
github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY=
|
||||||
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||||
|
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
|
||||||
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
||||||
|
github.com/spiffe/go-spiffe/v2 v2.8.1 h1:eXZMLsu+3MLEPJyGJkolqtVrteZfQdUpOWj6LTiDl/E=
|
||||||
github.com/spiffe/go-spiffe/v2 v2.8.1/go.mod h1:47Q0Q9/AqGha8QLHp+kxpH4Wca7X7EnOtlIJy3mxZ3U=
|
github.com/spiffe/go-spiffe/v2 v2.8.1/go.mod h1:47Q0Q9/AqGha8QLHp+kxpH4Wca7X7EnOtlIJy3mxZ3U=
|
||||||
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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
@@ -112,29 +217,57 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
|||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
github.com/tinode/jsonco v1.0.0 h1:zVcpjzDvjuA1G+HLrckI5EiiRyq9jgV3x37OQl6e5FE=
|
||||||
github.com/tinode/jsonco v1.0.0/go.mod h1:Bnavu3302Qfn2pILMNwASkelodgeew3IvDrbdzU84u8=
|
github.com/tinode/jsonco v1.0.0/go.mod h1:Bnavu3302Qfn2pILMNwASkelodgeew3IvDrbdzU84u8=
|
||||||
|
github.com/tinode/snowflake v1.0.0 h1:YciQ9ZKn1TrnvpS8yZErt044XJaxWVtR9aMO9rOZVOE=
|
||||||
github.com/tinode/snowflake v1.0.0/go.mod h1:5JiaCe3o7QdDeyRcAeZBGVghwRS+ygt2CF/hxmAoptQ=
|
github.com/tinode/snowflake v1.0.0/go.mod h1:5JiaCe3o7QdDeyRcAeZBGVghwRS+ygt2CF/hxmAoptQ=
|
||||||
|
github.com/twilio/twilio-go v1.30.9 h1:4W4GEV2q0sLQ9xsr1N/97JQlt0c82hZ0ij4qTErstv8=
|
||||||
github.com/twilio/twilio-go v1.30.9/go.mod h1:QbitvbvtkV77Jn4BABAKVmxabYSjMyQG4tHey9gfPqg=
|
github.com/twilio/twilio-go v1.30.9/go.mod h1:QbitvbvtkV77Jn4BABAKVmxabYSjMyQG4tHey9gfPqg=
|
||||||
|
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||||
|
github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs=
|
||||||
github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=
|
github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=
|
||||||
|
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
go.mongodb.org/mongo-driver v1.17.9 h1:IexDdCuuNJ3BHrELgBlyaH9p60JXAvdzWR128q+U5tU=
|
||||||
go.mongodb.org/mongo-driver v1.17.9/go.mod h1:LlOhpH5NUEfhxcAwG0UEkMqwYcc4JU18gtCdGudk/tQ=
|
go.mongodb.org/mongo-driver v1.17.9/go.mod h1:LlOhpH5NUEfhxcAwG0UEkMqwYcc4JU18gtCdGudk/tQ=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
|
go.opentelemetry.io/contrib/detectors/gcp v1.44.0 h1:NmLfL734pJhM0JKaYd2Y28+nY9dPRWYAAbxhRCrKXPw=
|
||||||
go.opentelemetry.io/contrib/detectors/gcp v1.44.0/go.mod h1:tNAsgd8avTGke1+MndXlU5Cru4PQ9Ai/cCNWQv/ZJ/s=
|
go.opentelemetry.io/contrib/detectors/gcp v1.44.0/go.mod h1:tNAsgd8avTGke1+MndXlU5Cru4PQ9Ai/cCNWQv/ZJ/s=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 h1:2yEATaop1/a1I4psnSLgWVPLWwCzkqWakgJy7xTDVy0=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0/go.mod h1:D7J12YRapIekYyPWgGPlA/23pRmpSEZC5xJC/TTLI9U=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0/go.mod h1:D7J12YRapIekYyPWgGPlA/23pRmpSEZC5xJC/TTLI9U=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
|
||||||
|
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
|
||||||
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
|
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.44.0 h1:hqxVTu/GtBF+vJ8d1fzW7fRxZFvgoDjWcxwwCaFDYpU=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.44.0/go.mod h1:z5fVEF4X5v0ESvlJqBrrFlBVoj5EQuefZpzsu7R+x5Q=
|
||||||
|
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
|
||||||
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
|
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
|
||||||
|
go.opentelemetry.io/otel/metric/x v0.66.0 h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA=
|
||||||
|
go.opentelemetry.io/otel/metric/x v0.66.0/go.mod h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
|
||||||
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
|
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
|
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
|
||||||
|
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
|
||||||
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
|
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
|
||||||
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
|
||||||
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-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-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
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.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
|
||||||
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
|
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
|
||||||
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/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
@@ -144,12 +277,15 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
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=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
||||||
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
||||||
|
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||||
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
|
||||||
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -161,6 +297,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||||
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@@ -168,7 +305,9 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|||||||
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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
|
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
|
||||||
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
|
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
|
||||||
|
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||||
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||||
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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
@@ -178,25 +317,39 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||||||
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=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||||
|
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||||
|
google.golang.org/api v0.287.0 h1:CQDMqUiqZZ0U/Yge3zyjAhNQ0OSYEH0PaA7l4xtEen4=
|
||||||
google.golang.org/api v0.287.0/go.mod h1:pPW85yt3Iuc3unkpaMhFtMmOqnTdCwCqEOaUlnuxRlQ=
|
google.golang.org/api v0.287.0/go.mod h1:pPW85yt3Iuc3unkpaMhFtMmOqnTdCwCqEOaUlnuxRlQ=
|
||||||
|
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||||
|
google.golang.org/genproto v0.0.0-20260630182238-925bb5da69e7 h1:lQG76ePMKmtujel4VIVMiFoHVWVNtJdawbCZJtWlVXU=
|
||||||
google.golang.org/genproto v0.0.0-20260630182238-925bb5da69e7/go.mod h1:LwlOWYBU335L+sR55UuR5fbbU8KmEX+3tUHf3SwMmhM=
|
google.golang.org/genproto v0.0.0-20260630182238-925bb5da69e7/go.mod h1:LwlOWYBU335L+sR55UuR5fbbU8KmEX+3tUHf3SwMmhM=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20260630182238-925bb5da69e7 h1:jQ9p21COKWjP3VwuFrNRiiOTMh3mPpN45R7SLrH/HUU=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20260630182238-925bb5da69e7/go.mod h1:KqHwBx2upmfa1XSi1WuRvC+2VGCLtooKkfmyvRbUmqA=
|
google.golang.org/genproto/googleapis/api v0.0.0-20260630182238-925bb5da69e7/go.mod h1:KqHwBx2upmfa1XSi1WuRvC+2VGCLtooKkfmyvRbUmqA=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260630182238-925bb5da69e7 h1:eM/YSd5bBFagF51o1E745Ta7RwzpW0h+z+QDNZOgmQ8=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260630182238-925bb5da69e7/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260630182238-925bb5da69e7/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
|
google.golang.org/grpc v1.82.0 h1:vguDnZUPjE26w09A63VoxZPnvPjB5Riyc0mkXPFmAIU=
|
||||||
google.golang.org/grpc v1.82.0/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA=
|
google.golang.org/grpc v1.82.0/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||||
|
gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
|
||||||
gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU=
|
gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU=
|
||||||
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-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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
||||||
|
gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.2 h1:tczPZjdz6soV2thcuq1IFOuNLrBUGonFyUXBbIWXWis=
|
||||||
gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.2/go.mod h1:c7Wo0IjB7JL9B9Avv0UZKorYJCUhiergpj3u1WtGT1E=
|
gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.2/go.mod h1:c7Wo0IjB7JL9B9Avv0UZKorYJCUhiergpj3u1WtGT1E=
|
||||||
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/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=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# keygen: API key generator
|
||||||
|
|
||||||
|
A command-line utility to generate an API key for [Tinode server](../server/)
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
* `sequence`: Sequential number of the API key. This value can be used to reject previously issued keys.
|
||||||
|
* `isroot`: Currently unused. Intended to designate key of a system administrator.
|
||||||
|
* `validate`: Key to validate: check previously issued key for validity.
|
||||||
|
* `salt`: [HMAC](https://en.wikipedia.org/wiki/HMAC) salt, 32 random bytes base64 standard encoded; must be present for key validation; optional when generating the key: if missing, a cryptographically-strong salt will be automatically generated.
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The API key is used to provide some protection from automatic scraping of server API and for identification of client applications.
|
||||||
|
|
||||||
|
* `API key` is used on the client side.
|
||||||
|
* `HMAC salt` is used on the server side to verify the API key.
|
||||||
|
|
||||||
|
Run the generator:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./keygen
|
||||||
|
```
|
||||||
|
|
||||||
|
Sample output:
|
||||||
|
|
||||||
|
```text
|
||||||
|
API key v1 seq1 [ordinary]: AQAAAAABAACGOIyP2vh5avSff5oVvMpk
|
||||||
|
HMAC salt: TC0Jzr8f28kAspXrb4UYccJUJ63b7CSA16n1qMxxGpw=
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy `HMAC salt` to `api_key_salt` parameter in your server [config file](https://github.com/tinode/chat/blob/master/server/tinode.conf).
|
||||||
|
Copy `API key` to the client applications:
|
||||||
|
|
||||||
|
* TinodeWeb: `API_KEY` in [config.js](https://github.com/tinode/webapp/blob/master/src/config.js)
|
||||||
|
* Tindroid: `API_KEY` in [Cache.java](https://github.com/tinode/tindroid/blob/master/app/src/main/java/co/tinode/tindroid/Cache.java)
|
||||||
|
* Tinodious: `kApiKey` in [SharedUtils.swift](https://github.com/tinode/ios/blob/master/TinodiosDB/SharedUtils.swift)
|
||||||
|
|
||||||
|
Rebuild the clients after changing the API key.
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/binary"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Generate API key
|
||||||
|
// Composition:
|
||||||
|
//
|
||||||
|
// [1:algorithm version][4:deprecated (used to be application ID)][2:key sequence][1:isRoot][16:signature] = 24 bytes
|
||||||
|
//
|
||||||
|
// convertible to base64 without padding.
|
||||||
|
// All integers are little-endian.
|
||||||
|
func main() {
|
||||||
|
version := flag.Int("sequence", 1, "Sequential number of the API key")
|
||||||
|
isRoot := flag.Int("isroot", 0, "Is this a root API key?")
|
||||||
|
apikey := flag.String("validate", "", "API key to validate")
|
||||||
|
hmacSalt := flag.String("salt", "", "HMAC salt, 32 random bytes base64-encoded")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *apikey != "" {
|
||||||
|
if *hmacSalt == "" {
|
||||||
|
log.Println("Error: must provide HMAC salt for key validation")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
os.Exit(validate(*apikey, *hmacSalt))
|
||||||
|
} else {
|
||||||
|
os.Exit(generate(*version, *isRoot, *hmacSalt))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// APIKEY_VERSION is algorithm version.
|
||||||
|
APIKEY_VERSION = 1
|
||||||
|
// APIKEY_APPID is deprecated.
|
||||||
|
APIKEY_APPID = 4
|
||||||
|
// APIKEY_SEQUENCE key serial number.
|
||||||
|
APIKEY_SEQUENCE = 2
|
||||||
|
// APIKEY_WHO is a Root user designator.
|
||||||
|
APIKEY_WHO = 1
|
||||||
|
// APIKEY_SIGNATURE is cryptographic signature.
|
||||||
|
APIKEY_SIGNATURE = 16
|
||||||
|
// APIKEY_LENGTH is total length of the key.
|
||||||
|
APIKEY_LENGTH = APIKEY_VERSION + APIKEY_APPID + APIKEY_SEQUENCE + APIKEY_WHO + APIKEY_SIGNATURE
|
||||||
|
)
|
||||||
|
|
||||||
|
func generate(sequence, isRoot int, hmacSaltB64 string) int {
|
||||||
|
var data [APIKEY_LENGTH]byte
|
||||||
|
var hmacSalt []byte
|
||||||
|
|
||||||
|
if hmacSaltB64 == "" {
|
||||||
|
hmacSalt = make([]byte, 32)
|
||||||
|
_, err := rand.Read(hmacSalt)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error: Failed to generate HMAC salt", err)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var err error
|
||||||
|
hmacSalt, err = base64.URLEncoding.DecodeString(hmacSaltB64)
|
||||||
|
if err != nil {
|
||||||
|
// Try standard base64 decoding
|
||||||
|
hmacSalt, err = base64.StdEncoding.DecodeString(hmacSaltB64)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error: Failed to decode HMAC salt", err)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Make sure the salt is base64std encoded: tinode.conf requires std encoding.
|
||||||
|
hmacSaltB64 = base64.StdEncoding.EncodeToString(hmacSalt)
|
||||||
|
|
||||||
|
// [1:algorithm version][4:appid][2:key sequence][1:isRoot]
|
||||||
|
data[0] = 1 // default algorithm
|
||||||
|
// deprecated
|
||||||
|
binary.LittleEndian.PutUint32(data[APIKEY_VERSION:], uint32(0))
|
||||||
|
binary.LittleEndian.PutUint16(data[APIKEY_VERSION+APIKEY_APPID:], uint16(sequence))
|
||||||
|
data[APIKEY_VERSION+APIKEY_APPID+APIKEY_SEQUENCE] = uint8(isRoot)
|
||||||
|
|
||||||
|
hasher := hmac.New(md5.New, hmacSalt)
|
||||||
|
hasher.Write(data[:APIKEY_VERSION+APIKEY_APPID+APIKEY_SEQUENCE+APIKEY_WHO])
|
||||||
|
signature := hasher.Sum(nil)
|
||||||
|
|
||||||
|
copy(data[APIKEY_VERSION+APIKEY_APPID+APIKEY_SEQUENCE+APIKEY_WHO:], signature)
|
||||||
|
|
||||||
|
var strIsRoot string
|
||||||
|
if isRoot == 1 {
|
||||||
|
strIsRoot = "ROOT"
|
||||||
|
} else {
|
||||||
|
strIsRoot = "ordinary"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("API key v%d seq%d [%s]: %s\nHMAC salt: %s\n", 1, sequence, strIsRoot,
|
||||||
|
base64.URLEncoding.EncodeToString(data[:]), hmacSaltB64)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func validate(apikey string, hmacSaltB64 string) int {
|
||||||
|
var version uint8
|
||||||
|
var deprecated uint32
|
||||||
|
var sequence uint16
|
||||||
|
var isRoot uint8
|
||||||
|
|
||||||
|
var strIsRoot string
|
||||||
|
|
||||||
|
hmacSalt, err := base64.URLEncoding.DecodeString(hmacSaltB64)
|
||||||
|
if err != nil {
|
||||||
|
// Try standard base64 decoding.
|
||||||
|
hmacSalt, err = base64.StdEncoding.DecodeString(hmacSaltB64)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error: Failed to decode HMAC salt", err)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if declen := base64.URLEncoding.DecodedLen(len(apikey)); declen != APIKEY_LENGTH {
|
||||||
|
log.Printf("Error: Invalid key length %d, expecting %d", declen, APIKEY_LENGTH)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := base64.URLEncoding.DecodeString(apikey)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error: Failed to decode key as base64-URL-encoded", err)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.NewReader(data)
|
||||||
|
binary.Read(buf, binary.LittleEndian, &version)
|
||||||
|
|
||||||
|
if version != 1 {
|
||||||
|
log.Println("Error: Unknown signature algorithm ", version)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
hasher := hmac.New(md5.New, hmacSalt)
|
||||||
|
hasher.Write(data[:APIKEY_VERSION+APIKEY_APPID+APIKEY_SEQUENCE+APIKEY_WHO])
|
||||||
|
|
||||||
|
if signature := hasher.Sum(nil); !bytes.Equal(data[APIKEY_VERSION+APIKEY_APPID+APIKEY_SEQUENCE+APIKEY_WHO:], signature) {
|
||||||
|
log.Println("Error: Invalid signature ", data, signature)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
// [1:algorithm version][4:deprecated][2:key sequence][1:isRoot]
|
||||||
|
binary.Read(buf, binary.LittleEndian, &deprecated)
|
||||||
|
binary.Read(buf, binary.LittleEndian, &sequence)
|
||||||
|
binary.Read(buf, binary.LittleEndian, &isRoot)
|
||||||
|
|
||||||
|
if isRoot == 1 {
|
||||||
|
strIsRoot = "ROOT"
|
||||||
|
} else {
|
||||||
|
strIsRoot = "ordinary"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Valid v%d seq%d, [%s]\n", version, sequence, strIsRoot)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Code in this folder is licensed under Apache 2.0
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# Tinode Load Testing
|
||||||
|
|
||||||
|
Content of this directory is for running rudimentary load tests of Tinode server. You need this only if you want to run your own load tests.
|
||||||
|
|
||||||
|
## Tsung
|
||||||
|
|
||||||
|
The `tsung.xml` is a configuration for [Tsung](http://tsung.erlang-projects.org/). The `tinode.beam` is an erlang binary required by the test to generate base64-encoded user-password pairs. The `tinode.erl` is the source for `tinode.beam` (`erlc tinode.erl` -> `tinode.beam`).
|
||||||
|
|
||||||
|
[Install Tsung](http://tsung.erlang-projects.org/user_manual/installation.html), then run the test
|
||||||
|
```
|
||||||
|
tsung -f ./tsung.xml start
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gatling
|
||||||
|
|
||||||
|
A similar loadtest scenario is also available in Gatling. The configuration file is `loadtest.scala`.
|
||||||
|
Run it with (after [installing Gatling](https://gatling.io/docs/current/installation/)):
|
||||||
|
```
|
||||||
|
gatling.sh -sf . -rsf . -rd "na" -s tinode.Loadtest
|
||||||
|
```
|
||||||
|
|
||||||
|
Currently, three tests are available:
|
||||||
|
|
||||||
|
* `tinode.Loadtest`: after connecting to server, retrieves user's subscriptions, and publishes a few messages to them one by one.
|
||||||
|
* `tinode.MeLoadtest`: attempts to max out `me` topic connections.
|
||||||
|
* `tinode.SingleTopicLoadtest`: connects to and publishes messages to the specified topic (typically, a group topic).
|
||||||
|
|
||||||
|
The script supports passing params via the `JAVA_OPTS` envvar.
|
||||||
|
|
||||||
|
Parameter name | Default value | Description
|
||||||
|
-------------- | ------------- | -------------
|
||||||
|
`num_sessions` | 10000 | Total number of sessions to connect to the server
|
||||||
|
`ramp` | 300 | Time period in seconds over which to ramp up the load (`0` to `num_sessions`).
|
||||||
|
`publish_count` | 10 | Number of messages that a user will publish to a topic it subscribes to.
|
||||||
|
`publish_interval` | 100 | Maximum period of time a user will wait between publishing subsequent messages to a topic.
|
||||||
|
`accounts` | users.csv | `tinode.Loadtest` and `tinode.SingleTopicLoadtest` only: Path to CSV file containing user accounts to use in loadtest (in format `username,password[,token]` (`token` field is optional).
|
||||||
|
`topic` | | `tinode.SingleTopicLoadtest` only: topic name to send load to.
|
||||||
|
`username` | | `tinode.MeLoadtest` only: user to subscribe to `me` topic.
|
||||||
|
`password` | | `tinode.MeLoadtest` only: user password.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
```shell
|
||||||
|
JAVA_OPTS="-Daccounts=users.csv -Dnum_sessions=100 -Dramp=10" gatling.sh -sf . -rsf . -rd "na" -s tinode.Loadtest
|
||||||
|
```
|
||||||
|
Ramps up load to 100 sessions listed in `users.csv` file over 10 seconds.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
JAVA_OPTS="-Dusername=user1 -Dpassword=user1123 -Dnum_sessions=10000 -Dramp=600" gatling.sh -sf . -rsf . -rd "na" -s tinode.MeLoadtest
|
||||||
|
```
|
||||||
|
Connects 10000 sessions to `me` topic for `user1` with password `user1123` over 600 seconds.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
JAVA_OPTS="-Dtopic=grpYOrcDwORhPg -Daccounts=users.csv -Dnum_sessions=10000 -Dramp=1000 -Dpublish_count=2 -Dpublish_interval=300" gatling.sh -sf . -rsf . -rd "na" -s tinode.SingleTopicLoadtest
|
||||||
|
```
|
||||||
|
Connects 10000 users (specified in `users.csv` file) to `grpYOrcDwORhPg` topic over 1000 seconds. Each user will publish 2 messages with interval up to 300 seconds.
|
||||||
|
|
||||||
|
This will be eventually packaged into a docker container.
|
||||||
|
|
||||||
|
### Experiments
|
||||||
|
|
||||||
|
We have tested our single-server Tinode synthetic setup with 50000 accounts on a standard `t3.xlarge` AWS box (4 vCPUs, 16GiB, 5Gbps network) with the `mysql` backend.
|
||||||
|
As the load increases, before starting to drop:
|
||||||
|
|
||||||
|
* The server can sustain 50000 concurrently connected sessions.
|
||||||
|
* An individual group topic was able to sustain 1500 concurrent sessions.
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
package tinode
|
||||||
|
|
||||||
|
import java.util.Base64
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
import scala.collection.JavaConverters._
|
||||||
|
import scala.collection._
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
import io.gatling.core.Predef._
|
||||||
|
import io.gatling.http.Predef._
|
||||||
|
|
||||||
|
class Loadtest extends TinodeBase {
|
||||||
|
// Input file can be set with the "accounts" java option.
|
||||||
|
// E.g. JAVA_OPTS="-Daccounts=/tmp/z.csv" gatling.sh -sf . -rsf . -rd "na" -s tinode.Loadtest
|
||||||
|
val feeder = csv(System.getProperty("accounts", "users.csv")).random
|
||||||
|
|
||||||
|
val scn = scenario("WebSocket")
|
||||||
|
.exec(ws("Connect WS").connect("/v0/channels?apikey=AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K"))
|
||||||
|
.exec(session => session.set("id", "tn-" + session.userId))
|
||||||
|
.pause(1)
|
||||||
|
.exec(hello)
|
||||||
|
.pause(1)
|
||||||
|
.feed(feeder)
|
||||||
|
.doIfOrElse({session =>
|
||||||
|
val uname = session("username").as[String]
|
||||||
|
var token = session("token").asOption[String]
|
||||||
|
if (token == None) {
|
||||||
|
token = tokenCache.get(uname)
|
||||||
|
}
|
||||||
|
token == None
|
||||||
|
}) { loginBasic } { loginToken }
|
||||||
|
.exitHereIfFailed
|
||||||
|
.exec(subMe)
|
||||||
|
.exitHereIfFailed
|
||||||
|
.exec(getSubs)
|
||||||
|
.exitHereIfFailed
|
||||||
|
.doIf({session =>
|
||||||
|
session.attributes.contains("subs")
|
||||||
|
}) {
|
||||||
|
exec { session =>
|
||||||
|
// Shuffle subscriptions.
|
||||||
|
val subs = session("subs").as[Vector[String]]
|
||||||
|
val shuffled = scala.util.Random.shuffle(subs.toList)
|
||||||
|
session.set("subs", shuffled)
|
||||||
|
}
|
||||||
|
.foreach("${subs}", "sub") {
|
||||||
|
exec(subTopic)
|
||||||
|
.exitHereIfFailed
|
||||||
|
.pause(0, 2)
|
||||||
|
.doIfOrElse({session =>
|
||||||
|
val topic = session("sub").as[String]
|
||||||
|
!topic.startsWith("chn")
|
||||||
|
}) { publish } { pause(5) }
|
||||||
|
.exec(leaveTopic)
|
||||||
|
.pause(0, 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.exec(ws("close-ws").close)
|
||||||
|
|
||||||
|
setUp(scn.inject(rampUsers(numSessions) during (rampPeriod.seconds))).protocols(httpProtocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
class MeLoadtest extends TinodeBase {
|
||||||
|
val username = System.getProperty("username", "user0")
|
||||||
|
val password = System.getProperty("password", "user0123")
|
||||||
|
|
||||||
|
val scn = scenario("WebSocket")
|
||||||
|
.exec(ws("Connect WS").connect("/v0/channels?apikey=AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K"))
|
||||||
|
.exec(session => session.set("id", "tn-" + session.userId))
|
||||||
|
.exec(session => session.set("username", username))
|
||||||
|
.exec(session => session.set("password", password))
|
||||||
|
.pause(1)
|
||||||
|
.exec(hello)
|
||||||
|
.pause(1)
|
||||||
|
.doIfOrElse({session =>
|
||||||
|
val uname = session("username").as[String]
|
||||||
|
val token = tokenCache.get(username)
|
||||||
|
token == None
|
||||||
|
}) { loginBasic } { loginToken }
|
||||||
|
.exitHereIfFailed
|
||||||
|
.exec(subMe)
|
||||||
|
.exitHereIfFailed
|
||||||
|
.exec(getSubs)
|
||||||
|
.exitHereIfFailed
|
||||||
|
.pause(1000)
|
||||||
|
.exec(ws("close-ws").close)
|
||||||
|
|
||||||
|
setUp(scn.inject(rampUsers(numSessions) during (rampPeriod.seconds))).protocols(httpProtocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
class SingleTopicLoadtest extends TinodeBase {
|
||||||
|
// Input file can be set with the "accounts" java option.
|
||||||
|
// E.g. JAVA_OPTS="-Daccounts=/tmp/z.csv" gatling.sh -sf . -rsf . -rd "na" -s tinode.Loadtest
|
||||||
|
val feeder = csv(System.getProperty("accounts", "users.csv")).random
|
||||||
|
val topic = System.getProperty("topic", "TOPIC_NAME")
|
||||||
|
|
||||||
|
val scn = scenario("WebSocket")
|
||||||
|
.exec(ws("Connect WS").connect("/v0/channels?apikey=AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K"))
|
||||||
|
.exec(session => session.set("id", "tn-" + session.userId))
|
||||||
|
.pause(1)
|
||||||
|
.exec(hello)
|
||||||
|
.pause(1)
|
||||||
|
.feed(feeder)
|
||||||
|
.doIfOrElse({session =>
|
||||||
|
val uname = session("username").as[String]
|
||||||
|
var token = session("token").asOption[String]
|
||||||
|
if (token == None) {
|
||||||
|
token = tokenCache.get(uname)
|
||||||
|
}
|
||||||
|
token == None
|
||||||
|
}) { loginBasic } { loginToken }
|
||||||
|
.exitHereIfFailed
|
||||||
|
.exec(subMe)
|
||||||
|
.exitHereIfFailed
|
||||||
|
.exec(getSubs)
|
||||||
|
.exitHereIfFailed
|
||||||
|
.doIf({session =>
|
||||||
|
session.attributes.contains("subs")
|
||||||
|
}) {
|
||||||
|
exec(session => session.set("sub", topic))
|
||||||
|
.exec(subTopic)
|
||||||
|
.exitHereIfFailed
|
||||||
|
.pause(0, 10)
|
||||||
|
.exec(publish)
|
||||||
|
.pause(15)
|
||||||
|
.exec(leaveTopic)
|
||||||
|
.pause(0, 3)
|
||||||
|
}
|
||||||
|
.exec(ws("close-ws").close)
|
||||||
|
|
||||||
|
setUp(scn.inject(rampUsers(numSessions) during (rampPeriod.seconds))).protocols(httpProtocol)
|
||||||
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,45 @@
|
|||||||
|
%% Support module for Tinode load testing with Tsung.
|
||||||
|
%% Compile using erlc then copy resulting .beam to
|
||||||
|
%% /usr/local/lib/erlang/lib/tsung-1.7.0/ebin/
|
||||||
|
%% Alternatively you can just leave it in the current
|
||||||
|
%% directory.
|
||||||
|
|
||||||
|
-module(tinode).
|
||||||
|
-export([rand_user_secret/1, shuffle/1, cache_token/2, read_token/1]).
|
||||||
|
|
||||||
|
%% Produces a secret for use in basic login.
|
||||||
|
rand_user_secret({Pid, DynData}) ->
|
||||||
|
base64:encode_to_string(get_rand_secret()).
|
||||||
|
|
||||||
|
|
||||||
|
%% Unexported. Picks a random user from a pre-defined list.
|
||||||
|
get_rand_secret() ->
|
||||||
|
case rand:uniform(6) of
|
||||||
|
1 -> "alice:alice123";
|
||||||
|
2 -> "bob:bob123";
|
||||||
|
3 -> "carol:carol123";
|
||||||
|
4 -> "dave:dave123";
|
||||||
|
5 -> "eve:eve123";
|
||||||
|
6 -> "frank:frank123"
|
||||||
|
end.
|
||||||
|
|
||||||
|
%% Shuffles a list randomly.
|
||||||
|
shuffle(L) ->
|
||||||
|
RandomList=[{rand:uniform(), X} || X <- L],
|
||||||
|
[X || {_,X} <- lists:sort(RandomList)].
|
||||||
|
|
||||||
|
%% Reads previously cached auth token for the specified user.
|
||||||
|
read_token(Uid) ->
|
||||||
|
{ok, LogDir} = application:get_env(tsung_controller, log_dir_real),
|
||||||
|
case file:read_file(filename:join(LogDir, Uid)) of
|
||||||
|
{ok, Data} -> string:trim(Data);
|
||||||
|
{error, _} -> ""
|
||||||
|
end.
|
||||||
|
|
||||||
|
%% Saves auth token for the specified user in the log directory.
|
||||||
|
cache_token(Uid, Token) ->
|
||||||
|
{ok, LogDir} = application:get_env(tsung_controller, log_dir_real),
|
||||||
|
{ok, File} = file:open(filename:join(LogDir, Uid), [write]),
|
||||||
|
file:write(File, Token),
|
||||||
|
file:close(File),
|
||||||
|
ok.
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
package tinode
|
||||||
|
|
||||||
|
import java.util.Base64
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
import scala.collection.JavaConverters._
|
||||||
|
import scala.collection._
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
import io.gatling.core.Predef._
|
||||||
|
import io.gatling.http.Predef._
|
||||||
|
|
||||||
|
class TinodeBase extends Simulation {
|
||||||
|
val httpProtocol = http
|
||||||
|
.baseUrl("http://localhost:6060")
|
||||||
|
.wsBaseUrl("ws://localhost:6060")
|
||||||
|
|
||||||
|
// Auth tokens to share between sessions.
|
||||||
|
val tokenCache : concurrent.Map[String, String] = new ConcurrentHashMap() asScala
|
||||||
|
// Total number of messages to publish to a topic.
|
||||||
|
val publishCount = Integer.getInteger("publish_count", 10).toInt
|
||||||
|
// Maximum interval between publishing messages to a topic.
|
||||||
|
val publishInterval = Integer.getInteger("publish_interval", 100).toInt
|
||||||
|
// Total number of sessions.
|
||||||
|
val numSessions = Integer.getInteger("num_sessions", 10000)
|
||||||
|
// Ramp up period (0 to numSessions) in seconds.
|
||||||
|
val rampPeriod = java.lang.Long.getLong("ramp", 300L)
|
||||||
|
|
||||||
|
val hello = exitBlockOnFail {
|
||||||
|
exec {
|
||||||
|
ws("hi").sendText(
|
||||||
|
"""{"hi":{"id":"afabb3","ver":"0.22.8","ua":"Gatling-Loadtest/1.0; gatling/1.7.0"}}"""
|
||||||
|
)
|
||||||
|
.await(15 seconds)(
|
||||||
|
ws.checkTextMessage("hi")
|
||||||
|
.matching(jsonPath("$.ctrl").find.exists)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val loginBasic = exitBlockOnFail {
|
||||||
|
exec { session =>
|
||||||
|
val uname = session("username").as[String]
|
||||||
|
val password = session("password").as[String]
|
||||||
|
val secret = new String(java.util.Base64.getEncoder.encode((uname + ":" + password).getBytes()))
|
||||||
|
session.set("secret", secret)
|
||||||
|
}
|
||||||
|
.exec {
|
||||||
|
ws("login").sendText(
|
||||||
|
"""{"login":{"id":"${id}-login","scheme":"basic","secret":"${secret}"}}"""
|
||||||
|
)
|
||||||
|
.await(15 seconds)(
|
||||||
|
ws.checkTextMessage("login-ctrl")
|
||||||
|
.matching(jsonPath("$.ctrl").find.exists)
|
||||||
|
.check(jsonPath("$.ctrl.params.token").saveAs("token"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.exec { session =>
|
||||||
|
val uname = session("username").as[String]
|
||||||
|
val token = session("token").as[String]
|
||||||
|
tokenCache.put(uname, token)
|
||||||
|
session
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val loginToken = exitBlockOnFail {
|
||||||
|
exec { session =>
|
||||||
|
val uname = session("username").as[String]
|
||||||
|
var token = session("token").asOption[String]
|
||||||
|
if (token == None) {
|
||||||
|
token = tokenCache.get(uname)
|
||||||
|
}
|
||||||
|
session.set("token", token.getOrElse(""))
|
||||||
|
}
|
||||||
|
.exec {
|
||||||
|
ws("login-token").sendText(
|
||||||
|
"""{"login":{"id":"${id}-login2","scheme":"token","secret":"${token}"}}"""
|
||||||
|
)
|
||||||
|
.await(15 seconds)(
|
||||||
|
ws.checkTextMessage("login-ctrl")
|
||||||
|
.matching(jsonPath("$.ctrl").find.exists)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val subMe = exitBlockOnFail {
|
||||||
|
exec {
|
||||||
|
ws("sub-me").sendText(
|
||||||
|
"""{"sub":{"id":"${id}-sub-me","topic":"me","get":{"what":"desc"}}}"""
|
||||||
|
)
|
||||||
|
.await(15 seconds)(
|
||||||
|
ws.checkTextMessage("sub-me-desc")
|
||||||
|
.matching(jsonPath("$.ctrl").find.exists)
|
||||||
|
.check(jsonPath("$.ctrl.code").ofType[Int].in(200 to 299))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val subTopic = exitBlockOnFail {
|
||||||
|
exec {
|
||||||
|
ws("sub-topic").sendText(
|
||||||
|
"""{"sub":{"id":"${id}-sub-${sub}","topic":"${sub}","get":{"what":"desc sub data del"}}}"""
|
||||||
|
)
|
||||||
|
.await(15 seconds)(
|
||||||
|
ws.checkTextMessage("sub-topic-ctrl")
|
||||||
|
.matching(jsonPath("$.ctrl").find.exists)
|
||||||
|
.check(jsonPath("$.ctrl.code").ofType[Int].in(200 to 299))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val publish = exitBlockOnFail {
|
||||||
|
exec {
|
||||||
|
repeat(publishCount, "i") {
|
||||||
|
exec {
|
||||||
|
ws("pub-topic").sendText(
|
||||||
|
"""{"pub":{"id":"${id}-pub-${sub}-${i}","topic":"${sub}","content":"This is a Gatling test ${i}"}}"""
|
||||||
|
)
|
||||||
|
.await(15 seconds)(
|
||||||
|
ws.checkTextMessage("pub-topic-ctrl")
|
||||||
|
.matching(jsonPath("$.ctrl").find.exists)
|
||||||
|
.check(jsonPath("$.ctrl.code").ofType[Int].in(200 to 299))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.pause(0, publishInterval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val getSubs = exitBlockOnFail {
|
||||||
|
exec {
|
||||||
|
ws("get-subs").sendText(
|
||||||
|
"""{"get":{"id":"${id}-get-subs","topic":"me","what":"sub"}}"""
|
||||||
|
)
|
||||||
|
.await(15 seconds)(
|
||||||
|
ws.checkTextMessage("save-subs")
|
||||||
|
.matching(jsonPath("$.meta.sub").find.exists)
|
||||||
|
.check(jsonPath("$.meta.sub[*].topic").findAll.saveAs("subs"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val leaveTopic = exitBlockOnFail {
|
||||||
|
exec {
|
||||||
|
ws("leave-topic").sendText(
|
||||||
|
"""{"leave":{"id":"${id}-leave-${sub}","topic":"${sub}"}}"""
|
||||||
|
)
|
||||||
|
.await(15 seconds)(
|
||||||
|
ws.checkTextMessage("sub-topic-ctrl")
|
||||||
|
.matching(jsonPath("$.ctrl").find.exists)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE tsung SYSTEM "/usr/local/share/tsung/tsung-1.0.dtd" []>
|
||||||
|
<tsung loglevel="notice" version="1.0" dumptraffic="false">
|
||||||
|
<clients>
|
||||||
|
<client host="localhost" use_controller_vm="true" maxusers="40000" />
|
||||||
|
</clients>
|
||||||
|
|
||||||
|
<servers>
|
||||||
|
<server host="127.0.0.1" port="6060" type="tcp" />
|
||||||
|
</servers>
|
||||||
|
|
||||||
|
<load>
|
||||||
|
|
||||||
|
<arrivalphase phase="1" duration="120" unit="second">
|
||||||
|
<users maxnumber="40000" arrivalrate="50" unit="second" />
|
||||||
|
</arrivalphase>
|
||||||
|
</load>
|
||||||
|
|
||||||
|
<sessions>
|
||||||
|
<session name="websocket" probability="100" type="ts_websocket">
|
||||||
|
<setdynvars sourcetype="random_string" length="4">
|
||||||
|
<var name="baseid" />
|
||||||
|
</setdynvars>
|
||||||
|
|
||||||
|
<request subst="true">
|
||||||
|
<websocket type="connect" path="/v0/channels?apikey=AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K">
|
||||||
|
<!--http_header name="X-Tinode-APIKey" value="AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K"/-->
|
||||||
|
</websocket>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request subst="true">
|
||||||
|
<websocket type="message">{"hi":{"id":"%%_baseid%%01","ver":"0.15","ua":"Tsung-Loadtest/1.0; tsung/1.7.0"}}</websocket>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<!-- Randomly pick a user. -->
|
||||||
|
<setdynvars sourcetype="eval"
|
||||||
|
code='fun({Pid, DynVars}) ->
|
||||||
|
tinode:rand_user_secret({Pid, DynVars})
|
||||||
|
end.'>
|
||||||
|
<var name="secret" />
|
||||||
|
</setdynvars>
|
||||||
|
|
||||||
|
<!-- Read auth token from the cache. -->
|
||||||
|
<setdynvars sourcetype="eval"
|
||||||
|
code='fun({Pid, DynVars}) ->
|
||||||
|
{ok, Secret} = ts_dynvars:lookup(secret, DynVars),
|
||||||
|
tinode:read_token(Secret)
|
||||||
|
end.'>
|
||||||
|
<var name="token" />
|
||||||
|
</setdynvars>
|
||||||
|
|
||||||
|
<!-- Token present. Authenticate with it. -->
|
||||||
|
<if var="token" neq="">
|
||||||
|
<request subst="true">
|
||||||
|
<match do="abort" when="nomatch">{"ctrl":.*"code":200.*}</match>
|
||||||
|
<websocket type="message">{"login":{"id":"%%_baseid%%02","scheme":"token","secret":"%%_token%%"}}</websocket>
|
||||||
|
</request>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<!-- else log in with user name and password. -->
|
||||||
|
<if var="token" eq="">
|
||||||
|
<request subst="true">
|
||||||
|
<match do="abort" when="nomatch">{"ctrl":.*"code":200.*}</match>
|
||||||
|
<dyn_variable name="token" re='^{"ctrl":.*"token":"([-A-Za-z0-9+\/=]+={0,3})".*}$'/>
|
||||||
|
<websocket type="message">{"login":{"id":"%%_baseid%%02","scheme":"basic","secret":"%%_secret%%"}}</websocket>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<!-- Save token in the cache. -->
|
||||||
|
<setdynvars sourcetype="eval"
|
||||||
|
code='fun({_, DynVars}) ->
|
||||||
|
{ok, Token} = ts_dynvars:lookup(token, DynVars),
|
||||||
|
{ok, Secret} = ts_dynvars:lookup(secret, DynVars),
|
||||||
|
tinode:cache_token(Secret, Token)
|
||||||
|
end.'>
|
||||||
|
<var name="dummy" />
|
||||||
|
</setdynvars>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<request subst="true">
|
||||||
|
<websocket type="message" frame="text">{"sub":{"id":"%%_baseid%%03","topic":"me","get":{"what":"desc"}}}</websocket>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<thinktime value="3" random="true"></thinktime>
|
||||||
|
|
||||||
|
<request subst="true">
|
||||||
|
<!--
|
||||||
|
Response looks like:
|
||||||
|
|
||||||
|
{"meta":{"id":"106691","topic":"me","ts":"2018-07-25T18:14:24.433Z","sub":[
|
||||||
|
{"updated":"2018-07-16T01:29:25.016Z","acs":{"given":47,"want":47,"mode":47},"topic":"grpOZcxbbwE7Hc","touched":"2018-07-16T17:32:12.48Z","seq":3},{"updated":"2018-07-16T01:35:25.016Z","acs":{"given":47,"want":47,"mode":47},"topic":"grpz6jDYiygVkI","touched":"2018-07-16T17:30:32.165Z","seq":22},{"updated":"2018-07-16T02:05:25.019Z","acs":{"given":47,"want":47,"mode":47},"topic":"grp8efPpvZoUQ4","touched":"2018-07-16T17:24:34.946Z","seq":1},{"updated":"2018-07-15T17:23:25.002Z","acs":{"given":31,"want":31,"mode":31},"topic":"usrlF7rSfaEx9c","touched":"2018-07-16T17:28:42.07Z","seq":9},{"updated":"2018-07-15T23:23:25.008Z","acs":{"given":16,"want":31,"mode":16},"topic":"usrddg3AFqzeEQ"},{"updated":"2018-07-15T23:53:25.009Z","acs":{"given":31,"want":31,"mode":31},"topic":"usrR6qq94MxLZ0","touched":"2018-07-16T17:30:03.93Z","seq":11},{"updated":"2018-07-15T23:56:25.01Z","acs":{"given":31,"want":31,"mode":31},"topic":"usriUhihEisbH8","touched":"2018-07-16T17:26:20.401Z","seq":9}]}}
|
||||||
|
-->
|
||||||
|
<dyn_variable name="subs" jsonpath="meta.sub[*].topic"/>
|
||||||
|
<websocket type="message" frame="text">{"get":{"id":"%%_baseid%%04","topic":"me","what":"sub"}}</websocket>
|
||||||
|
</request>
|
||||||
|
<setdynvars sourcetype="eval"
|
||||||
|
code="fun({Pid,DynVars})->
|
||||||
|
{ok,Subs}=ts_dynvars:lookup(subs,DynVars),
|
||||||
|
tinode:shuffle(Subs) end.">
|
||||||
|
<var name="shuffled_subs" />
|
||||||
|
</setdynvars>
|
||||||
|
|
||||||
|
<!-- main loop -->
|
||||||
|
<for from="1" to="100" incr="1" var="ctr">
|
||||||
|
<!-- Iterate over subscriptions -->
|
||||||
|
<foreach name="topicx" in="shuffled_subs">
|
||||||
|
<thinktime value="1" random="true"></thinktime>
|
||||||
|
|
||||||
|
<request subst="true">
|
||||||
|
<dyn_variable name="code" jsonpath="ctrl.code"/>
|
||||||
|
<websocket type="message" frame="text">{"sub":{"id":"%%_baseid%%%%_topicx%%%%_ctr%%","topic":"%%_topicx%%","get":{"what":"desc sub data del"}}}</websocket>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<if var="code" eq="200">
|
||||||
|
<for from="1" to="50" incr="1" var="counter">
|
||||||
|
<thinktime min="2" max="10" random="true"></thinktime>
|
||||||
|
|
||||||
|
<request subst="true">
|
||||||
|
<websocket type="message" frame="text">{"pub":{"id":"%%_baseid%%%%_topicx%%%%_ctr%%%%_counter%%","topic":"%%_topicx%%","content":"This is a Tsung test %%_baseid%% %%_counter%%"}}</websocket>
|
||||||
|
</request>
|
||||||
|
</for>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<request subst="true">
|
||||||
|
<websocket type="message" frame="text">{"leave":{"id":"%%_baseid%%%%_topicx%%%%_ctr%%","topic":"%%_topicx%%"}}</websocket>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
</foreach>
|
||||||
|
</for>
|
||||||
|
<!-- end main loop -->
|
||||||
|
|
||||||
|
<request>
|
||||||
|
<websocket type="close"></websocket>
|
||||||
|
</request>
|
||||||
|
</session>
|
||||||
|
</sessions>
|
||||||
|
</tsung>
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
username,password
|
||||||
|
alice,alice123
|
||||||
|
bob,bob123
|
||||||
|
carol,carol123
|
||||||
|
dave,dave123
|
||||||
|
eve,eve123
|
||||||
|
frank,frank123
|
||||||
|
|||||||
|
@@ -0,0 +1,2 @@
|
|||||||
|
Code in this folder and nested folders is licensed under Apache 2.0
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Monitoring Support
|
||||||
|
|
||||||
|
This directory contains code related to monitoring Tinode server. Supported monitoring services are
|
||||||
|
* [Prometheus](https://prometheus.io/)
|
||||||
|
* [InfluxDB](https://www.influxdata.com/)
|
||||||
|
|
||||||
|
See [exporter/README](./exporter/README.md) for more details.
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# Tinode Metric Exporter
|
||||||
|
|
||||||
|
This is a simple service which reads JSON monitoring data exposed by Tinode server using [expvar](https://golang.org/pkg/expvar/) and re-publishes it in other formats. Currently the supported formats are:
|
||||||
|
|
||||||
|
* [InfluxDB](https://www.influxdata.com/) [exporter](https://docs.influxdata.com/influxdb/v1.7/tools/api/#write-http-endpoint) **pushes** data to its target backend. This is the default mode.
|
||||||
|
* [Prometheus](https://prometheus.io/) [exporter](https://prometheus.io/docs/instrumenting/exporters/) which exports data in [prometheus format](https://prometheus.io/docs/concepts/data_model/). The Prometheus monitoring service is expected to **pull/scrape** data from the exporter.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Exporters are intended to run next to (pair with) Tinode servers: one Exporter per one Tinode server, i.e. a single Exporter provides metrics from a single Tinode server.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The exporters are configured by command-line flags:
|
||||||
|
|
||||||
|
### Common flags
|
||||||
|
* `serve_for` specifies which monitoring service the Exporter will gather metrics for; accepted values: `influxdb`, `prometheus`; default: `influxdb`.
|
||||||
|
* `tinode_addr` is the address where the Tinode instance publishes `expvar` data to scrape; default: `http://localhost:6060/stats/expvar`.
|
||||||
|
* `listen_at` is the hostname to bind to for serving the metrics; default: `:6222`.
|
||||||
|
* `instance` is the Exporter instance name (it may be exported to the upstream backend); default: `exporter`.
|
||||||
|
* `metric_list` is a comma-separated list of metrics to export; default: `Version,LiveTopics,TotalTopics,LiveSessions,ClusterLeader,TotalClusterNodes,LiveClusterNodes,memstats.Alloc`.
|
||||||
|
|
||||||
|
### InfluxDB
|
||||||
|
* `influx_push_addr` is the address of InfluxDB target server where the data gets sent; default: `http://localhost:9999/write`.
|
||||||
|
* `influx_db_version` is the version of InfluxDB (only 1.7 and 2.0 are supported); default: `1.7`.
|
||||||
|
* `influx_organization` specifies InfluxDB organization to push metrics as; default: `test`;
|
||||||
|
* `influx_bucket` is the name of InfluxDB storage bucket to store data in (used only in InfluxDB 2.0); default: `test`.
|
||||||
|
* `influx_auth_token` - InfluxDB authentication token; no default value.
|
||||||
|
* `influx_push_interval` - InfluxDB push interval in seconds; default: `30`.
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
Run InfluxDB Exporter as
|
||||||
|
```
|
||||||
|
./exporter \
|
||||||
|
--serve_for=influxdb \
|
||||||
|
--tinode_addr=http://localhost:6060/stats/expvar \
|
||||||
|
--listen_at=:6222 \
|
||||||
|
--instance=exp-0 \
|
||||||
|
--influx_push_addr=http://my-influxdb-backend.net/write \
|
||||||
|
--influx_db_version=1.7 \
|
||||||
|
--influx_organization=myOrg \
|
||||||
|
--influx_auth_token=myAuthToken123 \
|
||||||
|
--influx_push_interval=30
|
||||||
|
```
|
||||||
|
|
||||||
|
This exporter will push the collected metrics to the specified backend once every 30 seconds.
|
||||||
|
|
||||||
|
|
||||||
|
### Prometheus
|
||||||
|
* `prom_namespace` is a prefix to use for metrics names. If you are monitoring multiple tinode instances you may want to use different namespaces; default: `tinode`.
|
||||||
|
* `prom_metrics_path` is the path under which to expose the metrics for scraping; default: `/metrics`.
|
||||||
|
* `prom_timeout` is the Tinode connection timeout in seconds in response to Prometheus scrapes; default: `15`.
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
Run Prometheus Exporter as
|
||||||
|
```
|
||||||
|
./exporter \
|
||||||
|
--serve_for=prometheus \
|
||||||
|
--tinode_addr=http://localhost:6060/stats/expvar \
|
||||||
|
--listen_at=:6222 \
|
||||||
|
--instance=exp-0 \
|
||||||
|
--prom_namespace=tinode \
|
||||||
|
--prom_metrics_path=/metrics \
|
||||||
|
--prom_timeout=15
|
||||||
|
```
|
||||||
|
|
||||||
|
This exporter will serve data at path /metrics, on port 6222.
|
||||||
|
Once running, configure your Prometheus monitoring installation to collect data from this exporter.
|
||||||
|
|||||||
Regular → Executable
+68
@@ -0,0 +1,68 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# This scripts build and archives binaries and supporting files.
|
||||||
|
|
||||||
|
# Supported OSs: mac (darwin), windows, linux.
|
||||||
|
goplat=( darwin darwin windows linux )
|
||||||
|
|
||||||
|
# CPUs architectures: amd64 and arm64. The same order as OSs.
|
||||||
|
goarc=( amd64 arm64 amd64 amd64 )
|
||||||
|
|
||||||
|
# Number of platform+architectures.
|
||||||
|
buildCount=${#goplat[@]}
|
||||||
|
|
||||||
|
for line in $@; do
|
||||||
|
eval "$line"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Strip 'v' prefix as in v0.16.4 -> 0.16.4.
|
||||||
|
version=${tag#?}
|
||||||
|
|
||||||
|
if [ -z "$version" ]; then
|
||||||
|
# Get last git tag as release version. Tag looks like 'v.1.2.3', so strip 'v'.
|
||||||
|
version=`git describe --tags`
|
||||||
|
version=${version#?}
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Releasing exporter $version"
|
||||||
|
|
||||||
|
GOSRC=${GOPATH}/src/github.com/tinode
|
||||||
|
|
||||||
|
pushd ${GOSRC}/chat > /dev/null
|
||||||
|
|
||||||
|
# Make sure earlier builds are deleted.
|
||||||
|
rm -f ./releases/${version}/exporter*
|
||||||
|
|
||||||
|
for (( i=0; i<${buildCount}; i++ ));
|
||||||
|
do
|
||||||
|
plat="${goplat[$i]}"
|
||||||
|
arc="${goarc[$i]}"
|
||||||
|
|
||||||
|
echo "Building ${plat}/${arc}..."
|
||||||
|
|
||||||
|
# Remove possibly existing binaries from earlier builds.
|
||||||
|
rm -f ./releases/tmp/exporter*
|
||||||
|
|
||||||
|
# Environment to cros-compile for the platform.
|
||||||
|
env GOOS="${plat}" GOARCH="${arc}" go build \
|
||||||
|
-ldflags "-s -w -X main.buildstamp=`git describe --tags`" \
|
||||||
|
-o ./releases/tmp/exporter ./monitoring/exporter > /dev/null
|
||||||
|
|
||||||
|
# Build archive. All platforms but Windows use tar for archiving. Windows uses zip.
|
||||||
|
if [ "$plat" = "windows" ]; then
|
||||||
|
# Just copy the binary with .exe appended.
|
||||||
|
cp ./releases/tmp/exporter ./releases/${version}/exporter."${plat}-${arc}".exe
|
||||||
|
else
|
||||||
|
plat2=$plat
|
||||||
|
# Rename 'darwin' tp 'mac'
|
||||||
|
if [ "$plat" = "darwin" ]; then
|
||||||
|
plat2=mac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Just copy the binary.
|
||||||
|
cp ./releases/tmp/exporter ./releases/${version}/exporter."${plat2}-${arc}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
popd > /dev/null
|
||||||
|
|||||||
@@ -0,0 +1,211 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
"github.com/prometheus/common/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
type monitoringService int
|
||||||
|
|
||||||
|
const (
|
||||||
|
promService monitoringService = 1
|
||||||
|
influxService monitoringService = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Minimum interval between InfluxDB pushes in seconds.
|
||||||
|
minPushInterval = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
type promHTTPLogger struct{}
|
||||||
|
|
||||||
|
func (l promHTTPLogger) Println(v ...interface{}) {
|
||||||
|
log.Println(v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseMetricList(list string) []string {
|
||||||
|
metrics := strings.Split(list, ",")
|
||||||
|
for i, m := range metrics {
|
||||||
|
metrics[i] = strings.TrimSpace(m)
|
||||||
|
}
|
||||||
|
return metrics
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build version number defined by the compiler:
|
||||||
|
//
|
||||||
|
// -ldflags "-X main.buildstamp=value_to_assign_to_buildstamp"
|
||||||
|
//
|
||||||
|
// Reported to clients in response to {hi} message.
|
||||||
|
// For instance, to define the buildstamp as a timestamp of when the server was built add a
|
||||||
|
// flag to compiler command line:
|
||||||
|
//
|
||||||
|
// -ldflags "-X main.buildstamp=`date -u '+%Y%m%dT%H:%M:%SZ'`"
|
||||||
|
//
|
||||||
|
// or to set it to git tag:
|
||||||
|
//
|
||||||
|
// -ldflags "-X main.buildstamp=`git describe --tags`"
|
||||||
|
var buildstamp = "undef"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.Printf("Tinode metrics exporter.")
|
||||||
|
|
||||||
|
var (
|
||||||
|
serveFor = flag.String("serve_for", "influxdb",
|
||||||
|
"Monitoring service to gather metrics for. Available: influxdb, prometheus.")
|
||||||
|
tinodeAddr = flag.String("tinode_addr", "http://localhost:6060/stats/expvar",
|
||||||
|
"Address of the Tinode instance to scrape.")
|
||||||
|
listenAt = flag.String("listen_at", ":6222",
|
||||||
|
"Host name and port to listen for incoming requests on.")
|
||||||
|
metricList = flag.String("metric_list",
|
||||||
|
"Version,LiveTopics,TotalTopics,LiveSessions,ClusterLeader,TotalClusterNodes,LiveClusterNodes,memstats.Alloc",
|
||||||
|
"Comma-separated list of numeric metrics to scrape and export.")
|
||||||
|
histoMetricList = flag.String("histo_metric_list",
|
||||||
|
"RequestLatency,OutgoingMessageSize",
|
||||||
|
"Comma-separated list of histogram metrics to scrape and export.")
|
||||||
|
instance = flag.String("instance", "exporter",
|
||||||
|
"Exporter instance name.")
|
||||||
|
|
||||||
|
// Prometheus-specific arguments.
|
||||||
|
promNamespace = flag.String("prom_namespace", "tinode", "Prometheus namespace for metrics '<namespace>_...'")
|
||||||
|
promMetricsPath = flag.String("prom_metrics_path", "/metrics", "Path under which to expose metrics for Prometheus scrapes.")
|
||||||
|
promTimeout = flag.Int("prom_timeout", 15, "Tinode connection timeout in seconds in response to Prometheus scrapes.")
|
||||||
|
|
||||||
|
// InfluxDB-specific arguments.
|
||||||
|
influxPushAddr = flag.String("influx_push_addr", "http://localhost:9999/write",
|
||||||
|
"Address of InfluxDB target server where the data gets sent.")
|
||||||
|
influxDBVersion = flag.String("influx_db_version", "1.7",
|
||||||
|
"Version of InfluxDB (only 1.7 and 2.0 are supported).")
|
||||||
|
influxOrganization = flag.String("influx_organization", "test",
|
||||||
|
"InfluxDB organization to push metrics as.")
|
||||||
|
influxBucket = flag.String("influx_bucket", "test",
|
||||||
|
"InfluxDB storage bucket to store data in (used only in InfluxDB 2.0).")
|
||||||
|
influxAuthToken = flag.String("influx_auth_token", "",
|
||||||
|
"InfluxDB authentication token.")
|
||||||
|
influxPushInterval = flag.Int("influx_push_interval", 30,
|
||||||
|
"InfluxDB push interval in seconds.")
|
||||||
|
)
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
var service monitoringService
|
||||||
|
if *serveFor == "prometheus" {
|
||||||
|
service = promService
|
||||||
|
} else if *serveFor == "influxdb" {
|
||||||
|
service = influxService
|
||||||
|
} else {
|
||||||
|
log.Fatal("Invalid monitoring service:" + *serveFor + "; must be either \"prometheus\" or \"influxdb\"")
|
||||||
|
}
|
||||||
|
// Validate flags.
|
||||||
|
switch service {
|
||||||
|
case promService:
|
||||||
|
if *promMetricsPath == "/" {
|
||||||
|
log.Fatal("Serving metrics from / is not supported")
|
||||||
|
}
|
||||||
|
case influxService:
|
||||||
|
if *influxOrganization == "" {
|
||||||
|
log.Fatal("Must specify --influx_organization")
|
||||||
|
}
|
||||||
|
if *influxAuthToken == "" {
|
||||||
|
log.Fatal("Must specify --influx_auth_token")
|
||||||
|
}
|
||||||
|
if *influxBucket == "" {
|
||||||
|
log.Fatal("Must specify --influx_bucket")
|
||||||
|
}
|
||||||
|
if *influxDBVersion != "1.7" && *influxDBVersion != "2.0" {
|
||||||
|
log.Fatal("The --influx_db_version must be either 1.7 or 2.0")
|
||||||
|
}
|
||||||
|
if *influxPushInterval > 0 && *influxPushInterval < minPushInterval {
|
||||||
|
*influxPushInterval = minPushInterval
|
||||||
|
log.Println("The --influx_push_interval is too low, reset to", minPushInterval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Index page at web root.
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var servingPath string
|
||||||
|
switch service {
|
||||||
|
case promService:
|
||||||
|
servingPath = "<p>Prometheus exporter path: <a href='" + *promMetricsPath + "'>Metrics</a></p>"
|
||||||
|
case influxService:
|
||||||
|
servingPath = "<p>InfluxDB push path: <a href='/push'>Push</a></p>"
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte(`<html><head><title>Tinode Exporter</title></head><body>
|
||||||
|
<h1>Tinode Exporter</h1>
|
||||||
|
<p>Server type` + *serveFor + `</p>` + servingPath +
|
||||||
|
`<h2>Build</h2>
|
||||||
|
<pre>` + version.Info() + ` ` + version.BuildContext() + `</pre>
|
||||||
|
</body></html>`))
|
||||||
|
})
|
||||||
|
|
||||||
|
metrics := parseMetricList(*metricList)
|
||||||
|
histoMetrics := parseMetricList(*histoMetricList)
|
||||||
|
scraper := Scraper{address: *tinodeAddr, simpleMetrics: metrics, histogramMetrics: histoMetrics}
|
||||||
|
var serverTypeString string
|
||||||
|
// Create exporters.
|
||||||
|
switch service {
|
||||||
|
case promService:
|
||||||
|
serverTypeString = *serveFor
|
||||||
|
promExporter := NewPromExporter(*tinodeAddr, *promNamespace, time.Duration(*promTimeout)*time.Second, &scraper)
|
||||||
|
registry := prometheus.NewRegistry()
|
||||||
|
registry.MustRegister(promExporter)
|
||||||
|
http.Handle(*promMetricsPath,
|
||||||
|
promhttp.InstrumentMetricHandler(
|
||||||
|
registry,
|
||||||
|
promhttp.HandlerFor(
|
||||||
|
registry,
|
||||||
|
promhttp.HandlerOpts{
|
||||||
|
ErrorLog: &promHTTPLogger{},
|
||||||
|
Timeout: time.Duration(*promTimeout) * time.Second,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
case influxService:
|
||||||
|
serverTypeString = fmt.Sprintf("%s, version %s", *serveFor, *influxDBVersion)
|
||||||
|
influxDBExporter := NewInfluxDBExporter(*influxDBVersion, *influxPushAddr, *influxOrganization, *influxBucket,
|
||||||
|
*influxAuthToken, *instance, &scraper)
|
||||||
|
if *influxPushInterval > 0 {
|
||||||
|
go func() {
|
||||||
|
interval := time.Duration(*influxPushInterval) * time.Second
|
||||||
|
ch := time.Tick(interval)
|
||||||
|
for {
|
||||||
|
if _, ok := <-ch; ok {
|
||||||
|
if err := influxDBExporter.Push(); err != nil {
|
||||||
|
log.Println("InfluxDB push failed:", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
log.Println("InfluxDB push interval is zero. Will not push data automatically.")
|
||||||
|
}
|
||||||
|
// Forces a data push.
|
||||||
|
http.HandleFunc("/push", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var msg string
|
||||||
|
if err := influxDBExporter.Push(); err == nil {
|
||||||
|
msg = "HTTP 200 OK"
|
||||||
|
} else {
|
||||||
|
msg = err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte(`<html><head><title>Tinode Push</title></head><body>
|
||||||
|
<h1>Tinode Push</h1>
|
||||||
|
<pre>` + msg + `</pre>
|
||||||
|
</body></html>`))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Reading Tinode expvar from", *tinodeAddr)
|
||||||
|
log.Printf("Exporter running at %s. Server type %s", *listenAt, serverTypeString)
|
||||||
|
log.Fatalln(http.ListenAndServe(*listenAt, nil))
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,330 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PromExporter collects metrics in Prometheus format from a Tinode server.
|
||||||
|
type PromExporter struct {
|
||||||
|
address string
|
||||||
|
timeout time.Duration
|
||||||
|
namespace string
|
||||||
|
|
||||||
|
scraper *Scraper
|
||||||
|
|
||||||
|
up *prometheus.Desc
|
||||||
|
version *prometheus.Desc
|
||||||
|
topicsLive *prometheus.Desc
|
||||||
|
topicsTotal *prometheus.Desc
|
||||||
|
sessionsLive *prometheus.Desc
|
||||||
|
sessionsTotal *prometheus.Desc
|
||||||
|
|
||||||
|
numGoroutines *prometheus.Desc
|
||||||
|
|
||||||
|
incomingMessagesWebsockTotal *prometheus.Desc
|
||||||
|
outgoingMessagesWebsockTotal *prometheus.Desc
|
||||||
|
|
||||||
|
incomingMessagesLongpollTotal *prometheus.Desc
|
||||||
|
outgoingMessagesLongpollTotal *prometheus.Desc
|
||||||
|
|
||||||
|
incomingMessagesGrpcTotal *prometheus.Desc
|
||||||
|
outgoingMessagesGrpcTotal *prometheus.Desc
|
||||||
|
|
||||||
|
fileDownloadsTotal *prometheus.Desc
|
||||||
|
fileUploadsTotal *prometheus.Desc
|
||||||
|
|
||||||
|
ctrlCodesTotal2xx *prometheus.Desc
|
||||||
|
ctrlCodesTotal3xx *prometheus.Desc
|
||||||
|
ctrlCodesTotal4xx *prometheus.Desc
|
||||||
|
ctrlCodesTotal5xx *prometheus.Desc
|
||||||
|
|
||||||
|
clusterLeader *prometheus.Desc
|
||||||
|
clusterSize *prometheus.Desc
|
||||||
|
clusterNodesLive *prometheus.Desc
|
||||||
|
malloced *prometheus.Desc
|
||||||
|
requestLatencyMsCount *prometheus.Desc
|
||||||
|
outgoingMessageBytesCount *prometheus.Desc
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPromExporter returns an initialized Prometheus exporter.
|
||||||
|
func NewPromExporter(server, namespace string, timeout time.Duration, scraper *Scraper) *PromExporter {
|
||||||
|
return &PromExporter{
|
||||||
|
address: server,
|
||||||
|
timeout: timeout,
|
||||||
|
namespace: namespace,
|
||||||
|
scraper: scraper,
|
||||||
|
up: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "up"),
|
||||||
|
"If tinode instance is reachable.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
version: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "version"),
|
||||||
|
"The version of this tinode instance.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
topicsLive: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "topics_live_count"),
|
||||||
|
"Number of currently active topics.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
topicsTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "topics_total"),
|
||||||
|
"Total number of topics used during instance lifetime.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
sessionsLive: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "sessions_live_count"),
|
||||||
|
"Number of currently active sessions.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
sessionsTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "sessions_total"),
|
||||||
|
"Total number of sessions since instance start.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
numGoroutines: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "num_goroutines"),
|
||||||
|
"Number of currently spawned goroutines.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
incomingMessagesWebsockTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "incoming_messages_websock_total"),
|
||||||
|
"Total number of incoming messages via websocket.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
outgoingMessagesWebsockTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "outgoing_messages_websock_total"),
|
||||||
|
"Total number of outgoiing messages via websocket.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
incomingMessagesLongpollTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "incoming_messages_longpoll_total"),
|
||||||
|
"Total number of incoming messages via longpoll.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
outgoingMessagesLongpollTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "outgoing_messages_longpoll_total"),
|
||||||
|
"Total number of outgoiing messages via longpoll.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
incomingMessagesGrpcTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "incoming_messages_grpc_total"),
|
||||||
|
"Total number of incoming messages via grpc.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
outgoingMessagesGrpcTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "outgoing_messages_grpc_total"),
|
||||||
|
"Total number of outgoiing messages via grpc.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
fileDownloadsTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "file_downloads_total"),
|
||||||
|
"Total number of large file downloads.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
fileUploadsTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "file_uploads_total"),
|
||||||
|
"Total number of large file uploads.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
ctrlCodesTotal2xx: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "ctrl_codes_total_2xx"),
|
||||||
|
"Total number of 2xx ctrl response codes.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
ctrlCodesTotal3xx: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "ctrl_codes_total_3xx"),
|
||||||
|
"Total number of 3xx ctrl response codes.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
ctrlCodesTotal4xx: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "ctrl_codes_total_4xx"),
|
||||||
|
"Total number of 4xx ctrl response codes.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
ctrlCodesTotal5xx: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "ctrl_codes_total_5xx"),
|
||||||
|
"Total number of 5xx ctrl response codes.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
clusterLeader: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "cluster_leader"),
|
||||||
|
"If this cluster node is the cluster leader.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
clusterSize: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "cluster_size"),
|
||||||
|
"Configured number of cluster nodes.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
clusterNodesLive: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "cluster_nodes_live"),
|
||||||
|
"Number of cluster nodes believed to be live by the current node.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
malloced: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "malloced_bytes"),
|
||||||
|
"Number of bytes of memory allocated and in use.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
requestLatencyMsCount: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "request_latency_ms_count"),
|
||||||
|
"Request latency histogram (in ms).",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
outgoingMessageBytesCount: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", "outgoing_message_bytes"),
|
||||||
|
"Response size histogram (in bytes).",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describe describes all the metrics exported by the memcached exporter. It
|
||||||
|
// implements prometheus.Collector.
|
||||||
|
func (e *PromExporter) Describe(ch chan<- *prometheus.Desc) {
|
||||||
|
ch <- e.up
|
||||||
|
ch <- e.version
|
||||||
|
ch <- e.topicsLive
|
||||||
|
ch <- e.topicsTotal
|
||||||
|
ch <- e.sessionsLive
|
||||||
|
ch <- e.sessionsTotal
|
||||||
|
ch <- e.numGoroutines
|
||||||
|
|
||||||
|
ch <- e.incomingMessagesWebsockTotal
|
||||||
|
ch <- e.outgoingMessagesWebsockTotal
|
||||||
|
|
||||||
|
ch <- e.incomingMessagesLongpollTotal
|
||||||
|
ch <- e.outgoingMessagesLongpollTotal
|
||||||
|
|
||||||
|
ch <- e.incomingMessagesGrpcTotal
|
||||||
|
ch <- e.outgoingMessagesGrpcTotal
|
||||||
|
|
||||||
|
ch <- e.fileDownloadsTotal
|
||||||
|
ch <- e.fileUploadsTotal
|
||||||
|
|
||||||
|
ch <- e.ctrlCodesTotal2xx
|
||||||
|
ch <- e.ctrlCodesTotal3xx
|
||||||
|
ch <- e.ctrlCodesTotal4xx
|
||||||
|
ch <- e.ctrlCodesTotal5xx
|
||||||
|
|
||||||
|
ch <- e.clusterLeader
|
||||||
|
ch <- e.clusterSize
|
||||||
|
ch <- e.clusterNodesLive
|
||||||
|
ch <- e.malloced
|
||||||
|
|
||||||
|
ch <- e.requestLatencyMsCount
|
||||||
|
ch <- e.outgoingMessageBytesCount
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect fetches statistics from the configured Tinode instance, and
|
||||||
|
// delivers them as Prometheus metrics. It implements prometheus.Collector.
|
||||||
|
func (e *PromExporter) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
up := float64(1)
|
||||||
|
if stats, err := e.scraper.Scrape(); err != nil {
|
||||||
|
log.Println("Failed to fetch or parse response", err)
|
||||||
|
up = 0
|
||||||
|
} else {
|
||||||
|
if err := e.parseStats(ch, stats); err != nil {
|
||||||
|
up = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(e.up, prometheus.GaugeValue, up)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *PromExporter) parseStats(ch chan<- prometheus.Metric, stats map[string]interface{}) error {
|
||||||
|
err := firstError(
|
||||||
|
e.parseAndUpdate(ch, e.version, prometheus.GaugeValue, stats, "Version"),
|
||||||
|
e.parseAndUpdate(ch, e.topicsLive, prometheus.GaugeValue, stats, "LiveTopics"),
|
||||||
|
e.parseAndUpdate(ch, e.topicsTotal, prometheus.CounterValue, stats, "TotalTopics"),
|
||||||
|
e.parseAndUpdate(ch, e.sessionsLive, prometheus.GaugeValue, stats, "LiveSessions"),
|
||||||
|
e.parseAndUpdate(ch, e.sessionsTotal, prometheus.CounterValue, stats, "TotalSessions"),
|
||||||
|
e.parseAndUpdate(ch, e.numGoroutines, prometheus.GaugeValue, stats, "NumGoroutines"),
|
||||||
|
|
||||||
|
e.parseAndUpdate(ch, e.incomingMessagesWebsockTotal, prometheus.CounterValue, stats, "IncomingMessagesWebsockTotal"),
|
||||||
|
e.parseAndUpdate(ch, e.outgoingMessagesWebsockTotal, prometheus.CounterValue, stats, "OutgoingMessagesWebsockTotal"),
|
||||||
|
|
||||||
|
e.parseAndUpdate(ch, e.incomingMessagesLongpollTotal, prometheus.CounterValue, stats, "IncomingMessagesLongpollTotal"),
|
||||||
|
e.parseAndUpdate(ch, e.outgoingMessagesLongpollTotal, prometheus.CounterValue, stats, "OutgoingMessagesLongpollTotal"),
|
||||||
|
|
||||||
|
e.parseAndUpdate(ch, e.incomingMessagesGrpcTotal, prometheus.CounterValue, stats, "IncomingMessagesGrpcTotal"),
|
||||||
|
e.parseAndUpdate(ch, e.outgoingMessagesGrpcTotal, prometheus.CounterValue, stats, "OutgoingMessagesGrpcTotal"),
|
||||||
|
|
||||||
|
e.parseAndUpdate(ch, e.fileDownloadsTotal, prometheus.CounterValue, stats, "FileDownloadsTotal"),
|
||||||
|
e.parseAndUpdate(ch, e.fileUploadsTotal, prometheus.CounterValue, stats, "FileUploadsTotal"),
|
||||||
|
|
||||||
|
e.parseAndUpdate(ch, e.ctrlCodesTotal2xx, prometheus.CounterValue, stats, "CtrlCodesTotal2xx"),
|
||||||
|
e.parseAndUpdate(ch, e.ctrlCodesTotal3xx, prometheus.CounterValue, stats, "CtrlCodesTotal3xx"),
|
||||||
|
e.parseAndUpdate(ch, e.ctrlCodesTotal4xx, prometheus.CounterValue, stats, "CtrlCodesTotal4xx"),
|
||||||
|
e.parseAndUpdate(ch, e.ctrlCodesTotal5xx, prometheus.CounterValue, stats, "CtrlCodesTotal5xx"),
|
||||||
|
|
||||||
|
e.parseAndUpdate(ch, e.clusterLeader, prometheus.GaugeValue, stats, "ClusterLeader"),
|
||||||
|
e.parseAndUpdate(ch, e.clusterSize, prometheus.GaugeValue, stats, "TotalClusterNodes"),
|
||||||
|
e.parseAndUpdate(ch, e.clusterNodesLive, prometheus.GaugeValue, stats, "LiveClusterNodes"),
|
||||||
|
e.parseAndUpdate(ch, e.malloced, prometheus.GaugeValue, stats, "memstats.Alloc"),
|
||||||
|
|
||||||
|
e.parseAndUpdateHisto(ch, e.requestLatencyMsCount, stats, "RequestLatency"),
|
||||||
|
e.parseAndUpdateHisto(ch, e.outgoingMessageBytesCount, stats, "OutgoingMessageSize"),
|
||||||
|
)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *PromExporter) parseAndUpdate(ch chan<- prometheus.Metric, desc *prometheus.Desc, valueType prometheus.ValueType,
|
||||||
|
stats map[string]interface{}, key string) error {
|
||||||
|
v, err := parseNumeric(stats, key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ch <- prometheus.MustNewConstMetric(desc, valueType, v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *PromExporter) parseAndUpdateHisto(ch chan<- prometheus.Metric, desc *prometheus.Desc,
|
||||||
|
stats map[string]interface{}, key string) error {
|
||||||
|
h, err := parseHisto(stats, key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ch <- prometheus.MustNewConstHistogram(desc, h.count, h.sum, h.buckets)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func firstError(errs ...error) error {
|
||||||
|
for _, v := range errs {
|
||||||
|
if v != nil {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Scraper collects metrics from a tinode server.
|
||||||
|
type Scraper struct {
|
||||||
|
// Target Tinode server address.
|
||||||
|
address string
|
||||||
|
// List of simple numeric metrics to scrape.
|
||||||
|
simpleMetrics []string
|
||||||
|
// List of histogram metrics to scrape.
|
||||||
|
histogramMetrics []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Histogram struct.
|
||||||
|
type histogram struct {
|
||||||
|
count uint64
|
||||||
|
sum float64
|
||||||
|
buckets map[float64]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
var errKeyNotFound = errors.New("key not found")
|
||||||
|
var errMalformed = errors.New("input malformed")
|
||||||
|
|
||||||
|
// CollectRaw gathers all metrics from the configured Tinode instance,
|
||||||
|
// and returns them as a map.
|
||||||
|
func (s *Scraper) CollectRaw() (map[string]interface{}, error) {
|
||||||
|
stats, err := s.Scrape()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Failed to fetch or parse response", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
metrics, err := s.parseStatsRaw(stats)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
metrics["up"] = 1.0
|
||||||
|
return metrics, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scrape fetches the data from Tinode server using HTTP GET then decodes the response.
|
||||||
|
func (s *Scraper) Scrape() (map[string]interface{}, error) {
|
||||||
|
resp, err := http.Get(s.address)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Failed to connect to server", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var stats map[string]interface{}
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&stats)
|
||||||
|
return stats, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scraper) parseStatsRaw(stats map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
metrics := make(map[string]interface{})
|
||||||
|
for _, key := range s.simpleMetrics {
|
||||||
|
if val, err := parseNumeric(stats, key); err == nil {
|
||||||
|
metrics[key] = val
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, key := range s.histogramMetrics {
|
||||||
|
if val, err := parseHisto(stats, key); err == nil {
|
||||||
|
metrics[key] = val
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return metrics, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extracts a simple histogram from `stats` and returns a cumulative histogram
|
||||||
|
// corresponding to the simple histogram.
|
||||||
|
// Returns: (count, sum, buckets, error) tuple.
|
||||||
|
func parseHisto(stats map[string]interface{}, key string) (*histogram, error) {
|
||||||
|
// Histogram is presented as a json with the predefined fields: count, sum, count_per_bucket, bounds.
|
||||||
|
count, err := parseNumeric(stats, key+".count")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sum, err := parseNumeric(stats, key+".sum")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
buckets, err := parseList(stats, key+".count_per_bucket")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
bounds, err := parseList(stats, key+".bounds")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
n := len(buckets)
|
||||||
|
if n != len(bounds)+1 {
|
||||||
|
return nil, errMalformed
|
||||||
|
}
|
||||||
|
result := make(map[float64]uint64)
|
||||||
|
s := uint64(0)
|
||||||
|
for i, v := range bounds {
|
||||||
|
s += uint64(buckets[i])
|
||||||
|
result[v] = s
|
||||||
|
}
|
||||||
|
return &histogram{count: uint64(count), sum: sum, buckets: result}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extracts a list of numerics from `stats` for the given path.
|
||||||
|
func parseList(stats map[string]interface{}, path string) ([]float64, error) {
|
||||||
|
value, err := parseMetric(stats, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
listval, ok := value.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
log.Println("Value at path is not a float64 array:", path, value)
|
||||||
|
return nil, errMalformed
|
||||||
|
}
|
||||||
|
result := []float64{}
|
||||||
|
for _, v := range listval {
|
||||||
|
result = append(result, v.(float64))
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extracts a numeric from `stats` for the given path.
|
||||||
|
func parseNumeric(stats map[string]interface{}, path string) (float64, error) {
|
||||||
|
value, err := parseMetric(stats, path)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
floatval, ok := value.(float64)
|
||||||
|
if !ok {
|
||||||
|
log.Println("Value at path is not a float64:", path, value)
|
||||||
|
return 0, errKeyNotFound
|
||||||
|
}
|
||||||
|
return floatval, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extracts a metric from `stats` for the given path.
|
||||||
|
func parseMetric(stats map[string]interface{}, path string) (interface{}, error) {
|
||||||
|
parts := strings.Split(path, ".")
|
||||||
|
var value interface{}
|
||||||
|
var found bool
|
||||||
|
value = stats
|
||||||
|
for i := 0; i < len(parts); i++ {
|
||||||
|
subset, ok := value.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
log.Println("Invalid key path:", path)
|
||||||
|
return 0, errKeyNotFound
|
||||||
|
}
|
||||||
|
value, found = subset[parts[i]]
|
||||||
|
if !found {
|
||||||
|
log.Println("Invalid key path:", path, "(", parts[i], ")")
|
||||||
|
return 0, errKeyNotFound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Protocol Buffer and gRPC definitions
|
||||||
|
|
||||||
|
Definitions for Tinode [gRPC](https://grpc.io/) client and plugins.
|
||||||
|
|
||||||
|
Tinode gRPC clients must implement rpc service `Node`, Tinode plugins `Plugin`.
|
||||||
|
|
||||||
|
Generated `Go` and `Python` code is included. For a sample `Python` implementation of a command line client see [tn-cli](../tn-cli/).
|
||||||
|
For a partial plugin implementation see [chatbot](../chatbot/).
|
||||||
|
|
||||||
|
If you want to make changes, you have to install protobuffers tool chain and gRPC:
|
||||||
|
```
|
||||||
|
$ python -m pip install grpcio grpcio-tools googleapis-common-protos
|
||||||
|
```
|
||||||
|
|
||||||
|
To generate `Go` bindings add the following comment to your code and run `go generate` (your actual path to `/pbx` may be different):
|
||||||
|
```
|
||||||
|
//go:generate protoc --proto_path=../pbx --go_out=plugins=grpc:../pbx ../pbx/model.proto
|
||||||
|
```
|
||||||
|
|
||||||
|
To generate `Python` bindings:
|
||||||
|
```
|
||||||
|
python -m grpc_tools.protoc -I../pbx --python_out=. --grpc_python_out=. ../pbx/model.proto
|
||||||
|
```
|
||||||
|
|||||||
Regular → Executable
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
protoc --go_out=../pbx --go_opt=paths=source_relative --go-grpc_out=../pbx --go-grpc_opt=paths=source_relative model.proto
|
||||||
|
|||||||
+5846
File diff suppressed because it is too large
Load Diff
+660
@@ -0,0 +1,660 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package pbx;
|
||||||
|
option go_package = "github.com/tinode/chat/pbx";
|
||||||
|
|
||||||
|
// This is the methods that needs to be implemented by a gRPC client.
|
||||||
|
service Node {
|
||||||
|
// Client sends a stream of ClientMsg, server responds with a stream of ServerMsg
|
||||||
|
rpc MessageLoop(stream ClientMsg) returns (stream ServerMsg) {}
|
||||||
|
|
||||||
|
// Large file upload: a request with a stream of chunks.
|
||||||
|
rpc LargeFileReceive(stream FileUpReq) returns (FileUpResp) {}
|
||||||
|
|
||||||
|
// Large file file download: a response with a stream of chunks.
|
||||||
|
rpc LargeFileServe(FileDownReq) returns (stream FileDownResp) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin interface.
|
||||||
|
service Plugin {
|
||||||
|
// This plugin method is called by Tinode server for every message received from the clients. The
|
||||||
|
// method returns a ServerResp message. ServerResp.status tells Tinode server what to do next.
|
||||||
|
// See possible values for ServerResp.status in RespCode below.
|
||||||
|
rpc FireHose(ClientReq) returns (ServerResp) {}
|
||||||
|
|
||||||
|
// An alteranative user and topic discovery mechanism.
|
||||||
|
// A search request issued on a 'fnd' topic. This method is called to generate an alternative result set.
|
||||||
|
rpc Find(SearchQuery) returns (SearchFound) {}
|
||||||
|
|
||||||
|
// The following methods are for the Tinode server to report individual events.
|
||||||
|
|
||||||
|
// Account created, updated or deleted
|
||||||
|
rpc Account(AccountEvent) returns (Unused) {}
|
||||||
|
|
||||||
|
// Topic created, updated [or deleted -- not supported yet]
|
||||||
|
rpc Topic(TopicEvent) returns (Unused) {}
|
||||||
|
|
||||||
|
// Subscription created, updated or deleted
|
||||||
|
rpc Subscription(SubscriptionEvent) returns (Unused) {}
|
||||||
|
|
||||||
|
// Message published or deleted
|
||||||
|
rpc Message(MessageEvent) returns (Unused) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dummy placeholder message.
|
||||||
|
message Unused {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common client/server messages
|
||||||
|
|
||||||
|
// Authentication level
|
||||||
|
enum AuthLevel {
|
||||||
|
NONE = 0;
|
||||||
|
ANON = 10;
|
||||||
|
AUTH = 20;
|
||||||
|
ROOT = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client messages
|
||||||
|
|
||||||
|
// Topic default access mode
|
||||||
|
message DefaultAcsMode {
|
||||||
|
string auth = 1;
|
||||||
|
string anon = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual access mode
|
||||||
|
message AccessMode {
|
||||||
|
// Access mode requested by the user
|
||||||
|
string want = 1;
|
||||||
|
// Access mode granted to the user by the admin
|
||||||
|
string given = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSub: payload in set.sub request to update current subscription or invite another user, {sub.what} == "sub"
|
||||||
|
message SetSub {
|
||||||
|
// User affected by this request. Default (empty): current user
|
||||||
|
string user_id = 1;
|
||||||
|
|
||||||
|
// Access mode change, either Given or Want depending on context
|
||||||
|
string mode = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credentials such as email or phone number
|
||||||
|
message ClientCred {
|
||||||
|
// Credential type, i.e. `email` or `tel`.
|
||||||
|
string method = 1;
|
||||||
|
// Value to verify, i.e. `user@example.com` or `+18003287448`
|
||||||
|
string value = 2;
|
||||||
|
// Verification response
|
||||||
|
string response = 3;
|
||||||
|
// Request parameters, such as preferences or country code.
|
||||||
|
map<string, bytes> params = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDesc: C2S in set.what == "desc" and sub.init message
|
||||||
|
message SetDesc {
|
||||||
|
DefaultAcsMode default_acs = 1;
|
||||||
|
bytes public = 2;
|
||||||
|
bytes private = 3;
|
||||||
|
bytes trusted = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SeqRange {
|
||||||
|
int32 low = 1;
|
||||||
|
int32 hi = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetOpts {
|
||||||
|
// Timestamp in milliseconds since epoch 01/01/1970
|
||||||
|
int64 if_modified_since = 1;
|
||||||
|
// Limit search to this user ID
|
||||||
|
string user = 2;
|
||||||
|
// Limit search results to one topic;
|
||||||
|
string topic = 3;
|
||||||
|
// Load messages with seq id equal or greater than this
|
||||||
|
int32 since_id = 4;
|
||||||
|
// Load messages with seq id lower than this
|
||||||
|
int32 before_id = 5;
|
||||||
|
// Maximum number of results to return
|
||||||
|
int32 limit = 6;
|
||||||
|
// Load messages by id or ranges of ids
|
||||||
|
repeated SeqRange ranges = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetQuery {
|
||||||
|
string what = 1;
|
||||||
|
|
||||||
|
// Parameters of "desc" request
|
||||||
|
GetOpts desc = 2;
|
||||||
|
// Parameters of "sub" request
|
||||||
|
GetOpts sub = 3;
|
||||||
|
// Parameters of "data" request
|
||||||
|
GetOpts data = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SetQuery {
|
||||||
|
// Topic metadata, new topic & new subscriptions only
|
||||||
|
SetDesc desc = 1;
|
||||||
|
// Subscription parameters
|
||||||
|
SetSub sub = 2;
|
||||||
|
// Indexable tags
|
||||||
|
repeated string tags = 3;
|
||||||
|
// Credential being updated.
|
||||||
|
ClientCred cred = 4;
|
||||||
|
// Auxiliary data.
|
||||||
|
map<string, bytes> aux = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client handshake
|
||||||
|
message ClientHi {
|
||||||
|
string id = 1;
|
||||||
|
string user_agent = 2;
|
||||||
|
string ver = 3;
|
||||||
|
string device_id = 4;
|
||||||
|
string lang = 5;
|
||||||
|
string platform = 6;
|
||||||
|
bool background = 7;
|
||||||
|
string tenant = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// User creation message {acc}
|
||||||
|
message ClientAcc {
|
||||||
|
string id = 1;
|
||||||
|
// User being created or updated
|
||||||
|
string user_id = 2;
|
||||||
|
// The initial authentication scheme the account can use
|
||||||
|
string scheme = 3;
|
||||||
|
// Shared secret
|
||||||
|
bytes secret = 4;
|
||||||
|
// Authenticate session with the newly created account
|
||||||
|
bool login = 5;
|
||||||
|
// Indexable tags for user discovery
|
||||||
|
repeated string tags = 6;
|
||||||
|
// User initialization data when creating a new user, otherwise ignored
|
||||||
|
SetDesc desc = 7;
|
||||||
|
// Credentials for verification.
|
||||||
|
repeated ClientCred cred = 8;
|
||||||
|
// Authentication token used for resetting a password.
|
||||||
|
bytes token = 9;
|
||||||
|
// Account state: normal ("ok"), suspended
|
||||||
|
string state = 10;
|
||||||
|
// AuthLevel
|
||||||
|
AuthLevel auth_level = 11;
|
||||||
|
// Temporary auth params for one-off actions like password reset.
|
||||||
|
string tmp_scheme = 12;
|
||||||
|
bytes tmp_secret = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Login {login} message
|
||||||
|
message ClientLogin {
|
||||||
|
string id = 1;
|
||||||
|
// Authentication scheme
|
||||||
|
string scheme = 2;
|
||||||
|
// Shared secret
|
||||||
|
bytes secret = 3;
|
||||||
|
// Credentials for verification.
|
||||||
|
repeated ClientCred cred = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscription request {sub} message
|
||||||
|
message ClientSub {
|
||||||
|
string id = 1;
|
||||||
|
string topic = 2;
|
||||||
|
|
||||||
|
// mirrors {set}
|
||||||
|
SetQuery set_query = 3;
|
||||||
|
|
||||||
|
// mirrors {get}
|
||||||
|
GetQuery get_query = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsubscribe {leave} request message
|
||||||
|
message ClientLeave {
|
||||||
|
string id = 1;
|
||||||
|
string topic = 2;
|
||||||
|
bool unsub = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientPub is client's request to publish data to topic subscribers {pub}
|
||||||
|
message ClientPub {
|
||||||
|
string id = 1;
|
||||||
|
string topic = 2;
|
||||||
|
bool no_echo = 3;
|
||||||
|
map<string, bytes> head = 4;
|
||||||
|
bytes content = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query topic state {get}
|
||||||
|
message ClientGet {
|
||||||
|
string id = 1;
|
||||||
|
string topic = 2;
|
||||||
|
GetQuery query = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update topic state {set}
|
||||||
|
message ClientSet {
|
||||||
|
string id = 1;
|
||||||
|
string topic = 2;
|
||||||
|
SetQuery query = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientDel delete messages or topic
|
||||||
|
message ClientDel {
|
||||||
|
string id = 1;
|
||||||
|
string topic = 2;
|
||||||
|
// What to delete, either "msg" to delete messages (default) or "topic" to delete the topic or "sub"
|
||||||
|
// to delete a subscription to topic.
|
||||||
|
enum What {
|
||||||
|
// Invalid value. The name must be globally unique.
|
||||||
|
X0 = 0;
|
||||||
|
MSG = 1;
|
||||||
|
TOPIC = 2;
|
||||||
|
SUB = 3;
|
||||||
|
USER = 4;
|
||||||
|
CRED = 5;
|
||||||
|
}
|
||||||
|
What what = 3;
|
||||||
|
// Delete messages by id or range of ids
|
||||||
|
repeated SeqRange del_seq = 4;
|
||||||
|
// User ID of the subscription to delete
|
||||||
|
string user_id = 5;
|
||||||
|
// Credential to delete.
|
||||||
|
ClientCred cred = 6;
|
||||||
|
// Request to hard-delete messages for all users, if such option is available.
|
||||||
|
bool hard = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum InfoNote {
|
||||||
|
// Invalid value. The name must be globally unique.
|
||||||
|
X1 = 0;
|
||||||
|
READ = 1;
|
||||||
|
RECV = 2;
|
||||||
|
KP = 3;
|
||||||
|
CALL = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CallEvent {
|
||||||
|
// Invalid value. The name must be globally unique.
|
||||||
|
X2 = 0;
|
||||||
|
ACCEPT = 1;
|
||||||
|
ANSWER = 2;
|
||||||
|
HANG_UP = 3;
|
||||||
|
ICE_CANDIDATE = 4;
|
||||||
|
INVITE = 5;
|
||||||
|
OFFER = 6;
|
||||||
|
RINGING = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientNote is a client-generated notification for topic subscribers
|
||||||
|
message ClientNote {
|
||||||
|
string topic = 1;
|
||||||
|
// what is being reported: "recv" - message received, "read" - message read,
|
||||||
|
// "kp" - typing notification, "call" - voice/video call
|
||||||
|
InfoNote what = 2;
|
||||||
|
// Server-issued message ID being reported
|
||||||
|
int32 seq_id = 3;
|
||||||
|
// Client's count of unread messages to report back to the server. Used in push notifications on iOS.
|
||||||
|
int32 unread = 4;
|
||||||
|
// Call event.
|
||||||
|
CallEvent event = 5;
|
||||||
|
// Arbitrary json payload (used in video calls).
|
||||||
|
bytes payload = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ClientExtra {
|
||||||
|
repeated string attachments = 1;
|
||||||
|
// Root user may send messages on behalf of other users.
|
||||||
|
string on_behalf_of = 2;
|
||||||
|
AuthLevel auth_level = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ClientMsg {
|
||||||
|
oneof Message {
|
||||||
|
ClientHi hi = 1;
|
||||||
|
ClientAcc acc = 2;
|
||||||
|
ClientLogin login = 3;
|
||||||
|
ClientSub sub = 4;
|
||||||
|
ClientLeave leave = 5;
|
||||||
|
ClientPub pub = 6;
|
||||||
|
ClientGet get = 7;
|
||||||
|
ClientSet set = 8;
|
||||||
|
ClientDel del = 9;
|
||||||
|
ClientNote note = 10;
|
||||||
|
}
|
||||||
|
// Additional message parameters.
|
||||||
|
ClientExtra extra = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************
|
||||||
|
// Server response messages
|
||||||
|
|
||||||
|
// Credentials
|
||||||
|
message ServerCred {
|
||||||
|
// Credential type, i.e. `email` or `tel`.
|
||||||
|
string method = 1;
|
||||||
|
// Value to verify, i.e. `user@example.com` or `+18003287448`
|
||||||
|
string value = 2;
|
||||||
|
// Indicator that the credential is validated
|
||||||
|
bool done = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Topic description, S2C in Meta message
|
||||||
|
message TopicDesc {
|
||||||
|
int64 created_at = 1;
|
||||||
|
int64 updated_at = 2;
|
||||||
|
int64 touched_at = 3;
|
||||||
|
DefaultAcsMode defacs = 4;
|
||||||
|
AccessMode acs = 5;
|
||||||
|
int32 seq_id = 6;
|
||||||
|
int32 read_id = 7;
|
||||||
|
int32 recv_id = 8;
|
||||||
|
int32 del_id = 9;
|
||||||
|
bytes public = 10;
|
||||||
|
bytes private = 11;
|
||||||
|
string state = 12;
|
||||||
|
int64 state_at = 13;
|
||||||
|
bytes trusted = 14;
|
||||||
|
bool is_chan = 17; // 17!
|
||||||
|
bool online = 18;
|
||||||
|
|
||||||
|
// P2P only: other user's last online timestamp & user agent
|
||||||
|
int64 last_seen_time = 15;
|
||||||
|
string last_seen_user_agent = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgTopicSub: topic subscription details, sent in Meta message
|
||||||
|
message TopicSub {
|
||||||
|
int64 updated_at = 1;
|
||||||
|
int64 deleted_at = 2;
|
||||||
|
|
||||||
|
bool online = 3;
|
||||||
|
|
||||||
|
AccessMode acs = 4;
|
||||||
|
int32 read_id = 5;
|
||||||
|
int32 recv_id = 6;
|
||||||
|
bytes public = 7;
|
||||||
|
bytes trusted = 16; // 16!
|
||||||
|
bytes private = 8;
|
||||||
|
|
||||||
|
// Response to non-'me' topic
|
||||||
|
|
||||||
|
// Uid of the subscribed user
|
||||||
|
string user_id = 9;
|
||||||
|
|
||||||
|
// 'me' topic only
|
||||||
|
|
||||||
|
// Topic name of this subscription
|
||||||
|
string topic = 10;
|
||||||
|
int64 touched_at = 11;
|
||||||
|
// ID of the last {data} message in a topic
|
||||||
|
int32 seq_id = 12;
|
||||||
|
// Messages are deleted up to this ID
|
||||||
|
int32 del_id = 13;
|
||||||
|
|
||||||
|
// P2P topics only:
|
||||||
|
|
||||||
|
// Other user's last online timestamp & user agent
|
||||||
|
int64 last_seen_time = 14;
|
||||||
|
string last_seen_user_agent = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DelValues {
|
||||||
|
int32 del_id = 1;
|
||||||
|
repeated SeqRange del_seq = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// {ctrl} message
|
||||||
|
message ServerCtrl {
|
||||||
|
string id = 1;
|
||||||
|
string topic = 2;
|
||||||
|
int32 code = 3;
|
||||||
|
string text = 4;
|
||||||
|
map<string, bytes> params = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// {data} message
|
||||||
|
message ServerData {
|
||||||
|
string topic = 1;
|
||||||
|
// ID of the user who originated the message as {pub}, could be empty if sent by the system
|
||||||
|
string from_user_id = 2;
|
||||||
|
// Timestamp when the message was sent.
|
||||||
|
int64 timestamp = 7;
|
||||||
|
// Timestamp when the message was deleted or 0. Milliseconds since the epoch 01/01/1970
|
||||||
|
int64 deleted_at = 3;
|
||||||
|
int32 seq_id = 4;
|
||||||
|
map<string, bytes> head = 5;
|
||||||
|
bytes content = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// {pres} message
|
||||||
|
message ServerPres {
|
||||||
|
string topic = 1;
|
||||||
|
string src = 2;
|
||||||
|
enum What {
|
||||||
|
// Invalid value. The name must be globally unique.
|
||||||
|
X3 = 0;
|
||||||
|
ON = 1;
|
||||||
|
OFF = 2;
|
||||||
|
UA = 3;
|
||||||
|
UPD = 4;
|
||||||
|
GONE = 5;
|
||||||
|
ACS = 6;
|
||||||
|
TERM = 7;
|
||||||
|
MSG = 8;
|
||||||
|
READ = 9;
|
||||||
|
RECV = 10;
|
||||||
|
DEL = 11;
|
||||||
|
TAGS = 12;
|
||||||
|
AUX = 13;
|
||||||
|
}
|
||||||
|
What what = 3;
|
||||||
|
string user_agent = 4;
|
||||||
|
int32 seq_id = 5;
|
||||||
|
int32 del_id = 6;
|
||||||
|
repeated SeqRange del_seq = 7;
|
||||||
|
string target_user_id = 8;
|
||||||
|
string actor_user_id = 9;
|
||||||
|
AccessMode acs = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// {meta} message
|
||||||
|
message ServerMeta {
|
||||||
|
string id = 1;
|
||||||
|
string topic = 2;
|
||||||
|
|
||||||
|
TopicDesc desc = 3;
|
||||||
|
repeated TopicSub sub = 4;
|
||||||
|
DelValues del = 5;
|
||||||
|
repeated string tags = 6;
|
||||||
|
repeated ServerCred cred = 7;
|
||||||
|
map<string, bytes> aux = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// {info} message: server-side copy of ClientNote with From and optional Src added.
|
||||||
|
message ServerInfo {
|
||||||
|
string topic = 1;
|
||||||
|
string from_user_id = 2;
|
||||||
|
InfoNote what = 3;
|
||||||
|
int32 seq_id = 4;
|
||||||
|
string src = 5;
|
||||||
|
CallEvent event = 6;
|
||||||
|
bytes payload = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cumulative message
|
||||||
|
message ServerMsg {
|
||||||
|
oneof Message {
|
||||||
|
ServerCtrl ctrl = 1;
|
||||||
|
ServerData data = 2;
|
||||||
|
ServerPres pres = 3;
|
||||||
|
ServerMeta meta = 4;
|
||||||
|
ServerInfo info = 5;
|
||||||
|
}
|
||||||
|
// DEPRECATED. Will be removed soon.
|
||||||
|
// When response is sent to Root, send internal topic name too.
|
||||||
|
string topic = 6 [deprecated = true];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin response codes
|
||||||
|
enum RespCode {
|
||||||
|
// Instruct Tinode server to continue with default processing of the client request.
|
||||||
|
CONTINUE = 0;
|
||||||
|
// Drop the request as if the client did not send it
|
||||||
|
DROP = 1;
|
||||||
|
// Send the the provided srvmsg response to the client. ServerResp must contain non-zero
|
||||||
|
// srvmsg.
|
||||||
|
RESPOND = 2;
|
||||||
|
// Replace client's original request with the provided clmsg request then continue with
|
||||||
|
// processing. ServerResp must contain non-zero clmsg.
|
||||||
|
REPLACE = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ServerResp {
|
||||||
|
RespCode status = 1;
|
||||||
|
ServerMsg srvmsg = 2;
|
||||||
|
ClientMsg clmsg = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context message
|
||||||
|
message Session {
|
||||||
|
string session_id = 1;
|
||||||
|
string user_id = 2;
|
||||||
|
AuthLevel auth_level = 3;
|
||||||
|
string remote_addr = 4;
|
||||||
|
string user_agent = 5;
|
||||||
|
string device_id = 6;
|
||||||
|
string language = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ClientReq {
|
||||||
|
ClientMsg msg = 1;
|
||||||
|
Session sess = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search
|
||||||
|
|
||||||
|
message SearchQuery {
|
||||||
|
string user_id = 1;
|
||||||
|
string query = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SearchFound {
|
||||||
|
RespCode status = 1;
|
||||||
|
// New search query If status == REPLACE, otherwise unset.
|
||||||
|
string query = 2;
|
||||||
|
// Search results.
|
||||||
|
repeated TopicSub result = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRUD event messages
|
||||||
|
|
||||||
|
enum Crud {
|
||||||
|
CREATE = 0;
|
||||||
|
UPDATE = 1;
|
||||||
|
DELETE = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TopicEvent {
|
||||||
|
Crud action = 1;
|
||||||
|
string name = 2;
|
||||||
|
TopicDesc desc = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AccountEvent {
|
||||||
|
Crud action = 1;
|
||||||
|
string user_id = 2;
|
||||||
|
|
||||||
|
DefaultAcsMode default_acs = 3;
|
||||||
|
bytes public = 4;
|
||||||
|
|
||||||
|
// Indexable tags for user discovery
|
||||||
|
repeated string tags = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SubscriptionEvent {
|
||||||
|
Crud action = 1;
|
||||||
|
string topic = 2;
|
||||||
|
string user_id = 3;
|
||||||
|
|
||||||
|
int32 del_id = 4;
|
||||||
|
int32 read_id = 5;
|
||||||
|
int32 recv_id = 6;
|
||||||
|
|
||||||
|
AccessMode mode = 7;
|
||||||
|
|
||||||
|
bytes private = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MessageEvent {
|
||||||
|
Crud action = 1;
|
||||||
|
ServerData msg = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Large file handling.
|
||||||
|
|
||||||
|
message Auth {
|
||||||
|
string scheme = 1;
|
||||||
|
string secret = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// File description.
|
||||||
|
message FileMeta {
|
||||||
|
string name = 1;
|
||||||
|
string mime_type = 2;
|
||||||
|
string etag = 3;
|
||||||
|
int64 size = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// File upload request.
|
||||||
|
message FileUpReq {
|
||||||
|
// Request ID.
|
||||||
|
string id = 1;
|
||||||
|
// Request authentication credentials.
|
||||||
|
Auth auth = 2;
|
||||||
|
// The topic this upload belongs to.
|
||||||
|
string topic = 3;
|
||||||
|
// Uploaded metadata.
|
||||||
|
FileMeta meta = 4;
|
||||||
|
// File bytes being uploaded.
|
||||||
|
bytes content = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response to file upload.
|
||||||
|
message FileUpResp {
|
||||||
|
// Response ID.
|
||||||
|
string id = 1;
|
||||||
|
// Response code.
|
||||||
|
int32 code = 2;
|
||||||
|
// Response text.
|
||||||
|
string text = 3;
|
||||||
|
FileMeta meta = 4;
|
||||||
|
// New upload location.
|
||||||
|
string redir_url = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// File download request.
|
||||||
|
message FileDownReq {
|
||||||
|
// Request ID
|
||||||
|
string id = 1;
|
||||||
|
// Request authentication credentials.
|
||||||
|
Auth auth = 2;
|
||||||
|
// File URI to download.
|
||||||
|
string uri = 3;
|
||||||
|
// ETag
|
||||||
|
string if_modified = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response to file download.
|
||||||
|
message FileDownResp {
|
||||||
|
// Response ID.
|
||||||
|
string id = 1;
|
||||||
|
// Response code.
|
||||||
|
int32 code = 2;
|
||||||
|
// Response text.
|
||||||
|
string text = 3;
|
||||||
|
FileMeta meta = 4;
|
||||||
|
// File location.
|
||||||
|
string redir_url = 5;
|
||||||
|
// File bytes.
|
||||||
|
bytes content = 6;
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,560 @@
|
|||||||
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.2.0
|
||||||
|
// - protoc v3.21.12
|
||||||
|
// source: model.proto
|
||||||
|
|
||||||
|
package pbx
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
// Requires gRPC-Go v1.32.0 or later.
|
||||||
|
const _ = grpc.SupportPackageIsVersion7
|
||||||
|
|
||||||
|
// NodeClient is the client API for Node service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
type NodeClient interface {
|
||||||
|
// Client sends a stream of ClientMsg, server responds with a stream of ServerMsg
|
||||||
|
MessageLoop(ctx context.Context, opts ...grpc.CallOption) (Node_MessageLoopClient, error)
|
||||||
|
// Large file upload: a request with a stream of chunks.
|
||||||
|
LargeFileReceive(ctx context.Context, opts ...grpc.CallOption) (Node_LargeFileReceiveClient, error)
|
||||||
|
// Large file file download: a response with a stream of chunks.
|
||||||
|
LargeFileServe(ctx context.Context, in *FileDownReq, opts ...grpc.CallOption) (Node_LargeFileServeClient, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type nodeClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNodeClient(cc grpc.ClientConnInterface) NodeClient {
|
||||||
|
return &nodeClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nodeClient) MessageLoop(ctx context.Context, opts ...grpc.CallOption) (Node_MessageLoopClient, error) {
|
||||||
|
stream, err := c.cc.NewStream(ctx, &Node_ServiceDesc.Streams[0], "/pbx.Node/MessageLoop", opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
x := &nodeMessageLoopClient{stream}
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node_MessageLoopClient interface {
|
||||||
|
Send(*ClientMsg) error
|
||||||
|
Recv() (*ServerMsg, error)
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type nodeMessageLoopClient struct {
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nodeMessageLoopClient) Send(m *ClientMsg) error {
|
||||||
|
return x.ClientStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nodeMessageLoopClient) Recv() (*ServerMsg, error) {
|
||||||
|
m := new(ServerMsg)
|
||||||
|
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nodeClient) LargeFileReceive(ctx context.Context, opts ...grpc.CallOption) (Node_LargeFileReceiveClient, error) {
|
||||||
|
stream, err := c.cc.NewStream(ctx, &Node_ServiceDesc.Streams[1], "/pbx.Node/LargeFileReceive", opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
x := &nodeLargeFileReceiveClient{stream}
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node_LargeFileReceiveClient interface {
|
||||||
|
Send(*FileUpReq) error
|
||||||
|
CloseAndRecv() (*FileUpResp, error)
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type nodeLargeFileReceiveClient struct {
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nodeLargeFileReceiveClient) Send(m *FileUpReq) error {
|
||||||
|
return x.ClientStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nodeLargeFileReceiveClient) CloseAndRecv() (*FileUpResp, error) {
|
||||||
|
if err := x.ClientStream.CloseSend(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m := new(FileUpResp)
|
||||||
|
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *nodeClient) LargeFileServe(ctx context.Context, in *FileDownReq, opts ...grpc.CallOption) (Node_LargeFileServeClient, error) {
|
||||||
|
stream, err := c.cc.NewStream(ctx, &Node_ServiceDesc.Streams[2], "/pbx.Node/LargeFileServe", opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
x := &nodeLargeFileServeClient{stream}
|
||||||
|
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := x.ClientStream.CloseSend(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node_LargeFileServeClient interface {
|
||||||
|
Recv() (*FileDownResp, error)
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type nodeLargeFileServeClient struct {
|
||||||
|
grpc.ClientStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nodeLargeFileServeClient) Recv() (*FileDownResp, error) {
|
||||||
|
m := new(FileDownResp)
|
||||||
|
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeServer is the server API for Node service.
|
||||||
|
// All implementations must embed UnimplementedNodeServer
|
||||||
|
// for forward compatibility
|
||||||
|
type NodeServer interface {
|
||||||
|
// Client sends a stream of ClientMsg, server responds with a stream of ServerMsg
|
||||||
|
MessageLoop(Node_MessageLoopServer) error
|
||||||
|
// Large file upload: a request with a stream of chunks.
|
||||||
|
LargeFileReceive(Node_LargeFileReceiveServer) error
|
||||||
|
// Large file file download: a response with a stream of chunks.
|
||||||
|
LargeFileServe(*FileDownReq, Node_LargeFileServeServer) error
|
||||||
|
mustEmbedUnimplementedNodeServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedNodeServer must be embedded to have forward compatible implementations.
|
||||||
|
type UnimplementedNodeServer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (UnimplementedNodeServer) MessageLoop(Node_MessageLoopServer) error {
|
||||||
|
return status.Errorf(codes.Unimplemented, "method MessageLoop not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedNodeServer) LargeFileReceive(Node_LargeFileReceiveServer) error {
|
||||||
|
return status.Errorf(codes.Unimplemented, "method LargeFileReceive not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedNodeServer) LargeFileServe(*FileDownReq, Node_LargeFileServeServer) error {
|
||||||
|
return status.Errorf(codes.Unimplemented, "method LargeFileServe not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedNodeServer) mustEmbedUnimplementedNodeServer() {}
|
||||||
|
|
||||||
|
// UnsafeNodeServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to NodeServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafeNodeServer interface {
|
||||||
|
mustEmbedUnimplementedNodeServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterNodeServer(s grpc.ServiceRegistrar, srv NodeServer) {
|
||||||
|
s.RegisterService(&Node_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Node_MessageLoop_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||||
|
return srv.(NodeServer).MessageLoop(&nodeMessageLoopServer{stream})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node_MessageLoopServer interface {
|
||||||
|
Send(*ServerMsg) error
|
||||||
|
Recv() (*ClientMsg, error)
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type nodeMessageLoopServer struct {
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nodeMessageLoopServer) Send(m *ServerMsg) error {
|
||||||
|
return x.ServerStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nodeMessageLoopServer) Recv() (*ClientMsg, error) {
|
||||||
|
m := new(ClientMsg)
|
||||||
|
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Node_LargeFileReceive_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||||
|
return srv.(NodeServer).LargeFileReceive(&nodeLargeFileReceiveServer{stream})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node_LargeFileReceiveServer interface {
|
||||||
|
SendAndClose(*FileUpResp) error
|
||||||
|
Recv() (*FileUpReq, error)
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type nodeLargeFileReceiveServer struct {
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nodeLargeFileReceiveServer) SendAndClose(m *FileUpResp) error {
|
||||||
|
return x.ServerStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nodeLargeFileReceiveServer) Recv() (*FileUpReq, error) {
|
||||||
|
m := new(FileUpReq)
|
||||||
|
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Node_LargeFileServe_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||||
|
m := new(FileDownReq)
|
||||||
|
if err := stream.RecvMsg(m); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return srv.(NodeServer).LargeFileServe(m, &nodeLargeFileServeServer{stream})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node_LargeFileServeServer interface {
|
||||||
|
Send(*FileDownResp) error
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type nodeLargeFileServeServer struct {
|
||||||
|
grpc.ServerStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *nodeLargeFileServeServer) Send(m *FileDownResp) error {
|
||||||
|
return x.ServerStream.SendMsg(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node_ServiceDesc is the grpc.ServiceDesc for Node service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var Node_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "pbx.Node",
|
||||||
|
HandlerType: (*NodeServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{},
|
||||||
|
Streams: []grpc.StreamDesc{
|
||||||
|
{
|
||||||
|
StreamName: "MessageLoop",
|
||||||
|
Handler: _Node_MessageLoop_Handler,
|
||||||
|
ServerStreams: true,
|
||||||
|
ClientStreams: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StreamName: "LargeFileReceive",
|
||||||
|
Handler: _Node_LargeFileReceive_Handler,
|
||||||
|
ClientStreams: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StreamName: "LargeFileServe",
|
||||||
|
Handler: _Node_LargeFileServe_Handler,
|
||||||
|
ServerStreams: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Metadata: "model.proto",
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginClient is the client API for Plugin service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
type PluginClient interface {
|
||||||
|
// This plugin method is called by Tinode server for every message received from the clients. The
|
||||||
|
// method returns a ServerResp message. ServerResp.status tells Tinode server what to do next.
|
||||||
|
// See possible values for ServerResp.status in RespCode below.
|
||||||
|
FireHose(ctx context.Context, in *ClientReq, opts ...grpc.CallOption) (*ServerResp, error)
|
||||||
|
// An alteranative user and topic discovery mechanism.
|
||||||
|
// A search request issued on a 'fnd' topic. This method is called to generate an alternative result set.
|
||||||
|
Find(ctx context.Context, in *SearchQuery, opts ...grpc.CallOption) (*SearchFound, error)
|
||||||
|
// Account created, updated or deleted
|
||||||
|
Account(ctx context.Context, in *AccountEvent, opts ...grpc.CallOption) (*Unused, error)
|
||||||
|
// Topic created, updated [or deleted -- not supported yet]
|
||||||
|
Topic(ctx context.Context, in *TopicEvent, opts ...grpc.CallOption) (*Unused, error)
|
||||||
|
// Subscription created, updated or deleted
|
||||||
|
Subscription(ctx context.Context, in *SubscriptionEvent, opts ...grpc.CallOption) (*Unused, error)
|
||||||
|
// Message published or deleted
|
||||||
|
Message(ctx context.Context, in *MessageEvent, opts ...grpc.CallOption) (*Unused, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type pluginClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPluginClient(cc grpc.ClientConnInterface) PluginClient {
|
||||||
|
return &pluginClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) FireHose(ctx context.Context, in *ClientReq, opts ...grpc.CallOption) (*ServerResp, error) {
|
||||||
|
out := new(ServerResp)
|
||||||
|
err := c.cc.Invoke(ctx, "/pbx.Plugin/FireHose", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) Find(ctx context.Context, in *SearchQuery, opts ...grpc.CallOption) (*SearchFound, error) {
|
||||||
|
out := new(SearchFound)
|
||||||
|
err := c.cc.Invoke(ctx, "/pbx.Plugin/Find", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) Account(ctx context.Context, in *AccountEvent, opts ...grpc.CallOption) (*Unused, error) {
|
||||||
|
out := new(Unused)
|
||||||
|
err := c.cc.Invoke(ctx, "/pbx.Plugin/Account", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) Topic(ctx context.Context, in *TopicEvent, opts ...grpc.CallOption) (*Unused, error) {
|
||||||
|
out := new(Unused)
|
||||||
|
err := c.cc.Invoke(ctx, "/pbx.Plugin/Topic", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) Subscription(ctx context.Context, in *SubscriptionEvent, opts ...grpc.CallOption) (*Unused, error) {
|
||||||
|
out := new(Unused)
|
||||||
|
err := c.cc.Invoke(ctx, "/pbx.Plugin/Subscription", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) Message(ctx context.Context, in *MessageEvent, opts ...grpc.CallOption) (*Unused, error) {
|
||||||
|
out := new(Unused)
|
||||||
|
err := c.cc.Invoke(ctx, "/pbx.Plugin/Message", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginServer is the server API for Plugin service.
|
||||||
|
// All implementations must embed UnimplementedPluginServer
|
||||||
|
// for forward compatibility
|
||||||
|
type PluginServer interface {
|
||||||
|
// This plugin method is called by Tinode server for every message received from the clients. The
|
||||||
|
// method returns a ServerResp message. ServerResp.status tells Tinode server what to do next.
|
||||||
|
// See possible values for ServerResp.status in RespCode below.
|
||||||
|
FireHose(context.Context, *ClientReq) (*ServerResp, error)
|
||||||
|
// An alteranative user and topic discovery mechanism.
|
||||||
|
// A search request issued on a 'fnd' topic. This method is called to generate an alternative result set.
|
||||||
|
Find(context.Context, *SearchQuery) (*SearchFound, error)
|
||||||
|
// Account created, updated or deleted
|
||||||
|
Account(context.Context, *AccountEvent) (*Unused, error)
|
||||||
|
// Topic created, updated [or deleted -- not supported yet]
|
||||||
|
Topic(context.Context, *TopicEvent) (*Unused, error)
|
||||||
|
// Subscription created, updated or deleted
|
||||||
|
Subscription(context.Context, *SubscriptionEvent) (*Unused, error)
|
||||||
|
// Message published or deleted
|
||||||
|
Message(context.Context, *MessageEvent) (*Unused, error)
|
||||||
|
mustEmbedUnimplementedPluginServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedPluginServer must be embedded to have forward compatible implementations.
|
||||||
|
type UnimplementedPluginServer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (UnimplementedPluginServer) FireHose(context.Context, *ClientReq) (*ServerResp, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method FireHose not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedPluginServer) Find(context.Context, *SearchQuery) (*SearchFound, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method Find not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedPluginServer) Account(context.Context, *AccountEvent) (*Unused, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method Account not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedPluginServer) Topic(context.Context, *TopicEvent) (*Unused, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method Topic not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedPluginServer) Subscription(context.Context, *SubscriptionEvent) (*Unused, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method Subscription not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedPluginServer) Message(context.Context, *MessageEvent) (*Unused, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method Message not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedPluginServer) mustEmbedUnimplementedPluginServer() {}
|
||||||
|
|
||||||
|
// UnsafePluginServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to PluginServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafePluginServer interface {
|
||||||
|
mustEmbedUnimplementedPluginServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterPluginServer(s grpc.ServiceRegistrar, srv PluginServer) {
|
||||||
|
s.RegisterService(&Plugin_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Plugin_FireHose_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(ClientReq)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(PluginServer).FireHose(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/pbx.Plugin/FireHose",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(PluginServer).FireHose(ctx, req.(*ClientReq))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Plugin_Find_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(SearchQuery)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(PluginServer).Find(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/pbx.Plugin/Find",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(PluginServer).Find(ctx, req.(*SearchQuery))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Plugin_Account_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(AccountEvent)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(PluginServer).Account(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/pbx.Plugin/Account",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(PluginServer).Account(ctx, req.(*AccountEvent))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Plugin_Topic_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TopicEvent)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(PluginServer).Topic(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/pbx.Plugin/Topic",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(PluginServer).Topic(ctx, req.(*TopicEvent))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Plugin_Subscription_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(SubscriptionEvent)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(PluginServer).Subscription(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/pbx.Plugin/Subscription",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(PluginServer).Subscription(ctx, req.(*SubscriptionEvent))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Plugin_Message_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(MessageEvent)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(PluginServer).Message(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/pbx.Plugin/Message",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(PluginServer).Message(ctx, req.(*MessageEvent))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin_ServiceDesc is the grpc.ServiceDesc for Plugin service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var Plugin_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "pbx.Plugin",
|
||||||
|
HandlerType: (*PluginServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "FireHose",
|
||||||
|
Handler: _Plugin_FireHose_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Find",
|
||||||
|
Handler: _Plugin_Find_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Account",
|
||||||
|
Handler: _Plugin_Account_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Topic",
|
||||||
|
Handler: _Plugin_Topic_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Subscription",
|
||||||
|
Handler: _Plugin_Subscription_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Message",
|
||||||
|
Handler: _Plugin_Message_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "model.proto",
|
||||||
|
}
|
||||||
|
|||||||
Regular → Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Generate python gRPC bindings for Tinode. A command line parameter v=XX will use specified python version,
|
||||||
|
# i.e. ./generate-python.sh v=3 will use python3.
|
||||||
|
|
||||||
|
for line in $@; do
|
||||||
|
eval "$line"
|
||||||
|
done
|
||||||
|
|
||||||
|
python="python${v}"
|
||||||
|
|
||||||
|
# This generates python gRPC bindings for Tinode.
|
||||||
|
$python -m grpc_tools.protoc -I../pbx --python_out=../py_grpc/tinode_grpc --grpc_python_out=../py_grpc/tinode_grpc --pyi_out=../py_grpc/tinode_grpc ../pbx/model.proto
|
||||||
|
# Bindings are incompatible with Python packaging system. This is a fix.
|
||||||
|
$python py_fix.py
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# grpc-tools generates python 2 file which does not work with
|
||||||
|
# python3 packaging system. This is a fix.
|
||||||
|
|
||||||
|
model_pb2_grpc = "../py_grpc/tinode_grpc/model_pb2_grpc.py"
|
||||||
|
|
||||||
|
with open(model_pb2_grpc, "r") as fh:
|
||||||
|
content = fh.read().replace("\nimport model_pb2 as model__pb2",
|
||||||
|
"\nfrom . import model_pb2 as model__pb2")
|
||||||
|
|
||||||
|
with open(model_pb2_grpc,"w") as fh:
|
||||||
|
fh.write(content)
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
/build/
|
||||||
|
/dist/
|
||||||
|
/tinode_grpc/GIT_VERSION
|
||||||
|
*.egg-info/
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
The code in this folder is licensed under Apache 2.0
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Generated Protocol Buffer and gRPC files for [Tinode](https://github.com/tinode)
|
||||||
|
|
||||||
|
Generated Python code for [gRPC](https://grpc.io/) client and plugins.
|
||||||
|
|
||||||
|
gRPC clients must implement rpc service `Node`, plugins must implement `Plugin`.
|
||||||
|
|
||||||
|
For a sample implementation of a command line client see [tn-cli](https://github.com/tinode/chat/tree/master/tn-cli/).
|
||||||
|
For a partial plugin implementation see [chatbot](https://github.com/tinode/chat/tree/master/chatbot).
|
||||||
|
|
||||||
|
## Installing
|
||||||
|
|
||||||
|
Install the package by executing
|
||||||
|
```
|
||||||
|
pip install tinode_grpc
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Generating files
|
||||||
|
|
||||||
|
Don't modify included files directly. If you want to make changes, you have to install protobuffers tool chain and gRPC then generate the Python bindings from [`pbx/model.proto`](https://github.com/tinode/chat/tree/master/pbx/model.proto) (your path to `model.proto` may be different):
|
||||||
|
```
|
||||||
|
python -m grpc_tools.protoc -I../pbx --python_out=. --pyi_out=. --grpc_python_out=. ../pbx/model.proto
|
||||||
|
```
|
||||||
|
The generated `model_pb2_grpc.py` imports `model_pb2.py` as a module instead of a package which is incompatible with python3 packaging system. Use `../pbx/py_fix.py` to apply a fix. This is only needed if you want to repackage the generated files.
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=45", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "tinode_grpc"
|
||||||
|
description = "Tinode gRPC bindings."
|
||||||
|
authors = [
|
||||||
|
{name = "Tinode Authors", email = "info@tinode.co"},
|
||||||
|
]
|
||||||
|
license = "Apache-2.0"
|
||||||
|
readme = "README.md"
|
||||||
|
keywords = ["chat", "messaging", "messenger", "im", "tinode"]
|
||||||
|
classifiers = [
|
||||||
|
"Programming Language :: Python :: 2",
|
||||||
|
"Programming Language :: Python :: 2.7",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.5",
|
||||||
|
"Programming Language :: Python :: 3.6",
|
||||||
|
"Programming Language :: Python :: 3.7",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Operating System :: OS Independent",
|
||||||
|
"Topic :: Communications :: Chat",
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
"protobuf>=3.6.1",
|
||||||
|
"grpcio>=1.19.0",
|
||||||
|
]
|
||||||
|
dynamic = ["version"]
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Homepage = "https://github.com/tinode/chat"
|
||||||
|
Repository = "https://github.com/tinode/chat"
|
||||||
|
Issues = "https://github.com/tinode/chat/issues"
|
||||||
|
|
||||||
|
[tool.setuptools]
|
||||||
|
packages = ["tinode_grpc"]
|
||||||
|
|
||||||
|
[tool.setuptools.package-data]
|
||||||
|
"*" = ["GIT_VERSION", "*.pyi"]
|
||||||
|
|
||||||
|
# Alternative version handling if you want to keep reading from GIT_VERSION file
|
||||||
|
[tool.setuptools.dynamic]
|
||||||
|
version = {file = "tinode_grpc/GIT_VERSION"}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
from . import model_pb2 as pb
|
||||||
|
from . import model_pb2_grpc as pbx
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,832 @@
|
|||||||
|
from google.protobuf.internal import containers as _containers
|
||||||
|
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
|
||||||
|
from google.protobuf import descriptor as _descriptor
|
||||||
|
from google.protobuf import message as _message
|
||||||
|
from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
|
||||||
|
|
||||||
|
DESCRIPTOR: _descriptor.FileDescriptor
|
||||||
|
|
||||||
|
class AuthLevel(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||||
|
__slots__ = []
|
||||||
|
NONE: _ClassVar[AuthLevel]
|
||||||
|
ANON: _ClassVar[AuthLevel]
|
||||||
|
AUTH: _ClassVar[AuthLevel]
|
||||||
|
ROOT: _ClassVar[AuthLevel]
|
||||||
|
|
||||||
|
class InfoNote(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||||
|
__slots__ = []
|
||||||
|
X1: _ClassVar[InfoNote]
|
||||||
|
READ: _ClassVar[InfoNote]
|
||||||
|
RECV: _ClassVar[InfoNote]
|
||||||
|
KP: _ClassVar[InfoNote]
|
||||||
|
CALL: _ClassVar[InfoNote]
|
||||||
|
|
||||||
|
class CallEvent(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||||
|
__slots__ = []
|
||||||
|
X2: _ClassVar[CallEvent]
|
||||||
|
ACCEPT: _ClassVar[CallEvent]
|
||||||
|
ANSWER: _ClassVar[CallEvent]
|
||||||
|
HANG_UP: _ClassVar[CallEvent]
|
||||||
|
ICE_CANDIDATE: _ClassVar[CallEvent]
|
||||||
|
INVITE: _ClassVar[CallEvent]
|
||||||
|
OFFER: _ClassVar[CallEvent]
|
||||||
|
RINGING: _ClassVar[CallEvent]
|
||||||
|
|
||||||
|
class RespCode(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||||
|
__slots__ = []
|
||||||
|
CONTINUE: _ClassVar[RespCode]
|
||||||
|
DROP: _ClassVar[RespCode]
|
||||||
|
RESPOND: _ClassVar[RespCode]
|
||||||
|
REPLACE: _ClassVar[RespCode]
|
||||||
|
|
||||||
|
class Crud(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||||
|
__slots__ = []
|
||||||
|
CREATE: _ClassVar[Crud]
|
||||||
|
UPDATE: _ClassVar[Crud]
|
||||||
|
DELETE: _ClassVar[Crud]
|
||||||
|
NONE: AuthLevel
|
||||||
|
ANON: AuthLevel
|
||||||
|
AUTH: AuthLevel
|
||||||
|
ROOT: AuthLevel
|
||||||
|
X1: InfoNote
|
||||||
|
READ: InfoNote
|
||||||
|
RECV: InfoNote
|
||||||
|
KP: InfoNote
|
||||||
|
CALL: InfoNote
|
||||||
|
X2: CallEvent
|
||||||
|
ACCEPT: CallEvent
|
||||||
|
ANSWER: CallEvent
|
||||||
|
HANG_UP: CallEvent
|
||||||
|
ICE_CANDIDATE: CallEvent
|
||||||
|
INVITE: CallEvent
|
||||||
|
OFFER: CallEvent
|
||||||
|
RINGING: CallEvent
|
||||||
|
CONTINUE: RespCode
|
||||||
|
DROP: RespCode
|
||||||
|
RESPOND: RespCode
|
||||||
|
REPLACE: RespCode
|
||||||
|
CREATE: Crud
|
||||||
|
UPDATE: Crud
|
||||||
|
DELETE: Crud
|
||||||
|
|
||||||
|
class Unused(_message.Message):
|
||||||
|
__slots__ = []
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
class DefaultAcsMode(_message.Message):
|
||||||
|
__slots__ = ["auth", "anon"]
|
||||||
|
AUTH_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
ANON_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
auth: str
|
||||||
|
anon: str
|
||||||
|
def __init__(self, auth: _Optional[str] = ..., anon: _Optional[str] = ...) -> None: ...
|
||||||
|
|
||||||
|
class AccessMode(_message.Message):
|
||||||
|
__slots__ = ["want", "given"]
|
||||||
|
WANT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
GIVEN_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
want: str
|
||||||
|
given: str
|
||||||
|
def __init__(self, want: _Optional[str] = ..., given: _Optional[str] = ...) -> None: ...
|
||||||
|
|
||||||
|
class SetSub(_message.Message):
|
||||||
|
__slots__ = ["user_id", "mode"]
|
||||||
|
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
MODE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
user_id: str
|
||||||
|
mode: str
|
||||||
|
def __init__(self, user_id: _Optional[str] = ..., mode: _Optional[str] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientCred(_message.Message):
|
||||||
|
__slots__ = ["method", "value", "response", "params"]
|
||||||
|
class ParamsEntry(_message.Message):
|
||||||
|
__slots__ = ["key", "value"]
|
||||||
|
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
key: str
|
||||||
|
value: bytes
|
||||||
|
def __init__(self, key: _Optional[str] = ..., value: _Optional[bytes] = ...) -> None: ...
|
||||||
|
METHOD_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
RESPONSE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PARAMS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
method: str
|
||||||
|
value: str
|
||||||
|
response: str
|
||||||
|
params: _containers.ScalarMap[str, bytes]
|
||||||
|
def __init__(self, method: _Optional[str] = ..., value: _Optional[str] = ..., response: _Optional[str] = ..., params: _Optional[_Mapping[str, bytes]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class SetDesc(_message.Message):
|
||||||
|
__slots__ = ["default_acs", "public", "private", "trusted"]
|
||||||
|
DEFAULT_ACS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PUBLIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PRIVATE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TRUSTED_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
default_acs: DefaultAcsMode
|
||||||
|
public: bytes
|
||||||
|
private: bytes
|
||||||
|
trusted: bytes
|
||||||
|
def __init__(self, default_acs: _Optional[_Union[DefaultAcsMode, _Mapping]] = ..., public: _Optional[bytes] = ..., private: _Optional[bytes] = ..., trusted: _Optional[bytes] = ...) -> None: ...
|
||||||
|
|
||||||
|
class SeqRange(_message.Message):
|
||||||
|
__slots__ = ["low", "hi"]
|
||||||
|
LOW_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
HI_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
low: int
|
||||||
|
hi: int
|
||||||
|
def __init__(self, low: _Optional[int] = ..., hi: _Optional[int] = ...) -> None: ...
|
||||||
|
|
||||||
|
class GetOpts(_message.Message):
|
||||||
|
__slots__ = ["if_modified_since", "user", "topic", "since_id", "before_id", "limit", "ranges"]
|
||||||
|
IF_MODIFIED_SINCE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
USER_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SINCE_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
BEFORE_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
LIMIT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
RANGES_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
if_modified_since: int
|
||||||
|
user: str
|
||||||
|
topic: str
|
||||||
|
since_id: int
|
||||||
|
before_id: int
|
||||||
|
limit: int
|
||||||
|
ranges: _containers.RepeatedCompositeFieldContainer[SeqRange]
|
||||||
|
def __init__(self, if_modified_since: _Optional[int] = ..., user: _Optional[str] = ..., topic: _Optional[str] = ..., since_id: _Optional[int] = ..., before_id: _Optional[int] = ..., limit: _Optional[int] = ..., ranges: _Optional[_Iterable[_Union[SeqRange, _Mapping]]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class GetQuery(_message.Message):
|
||||||
|
__slots__ = ["what", "desc", "sub", "data"]
|
||||||
|
WHAT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DESC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SUB_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
what: str
|
||||||
|
desc: GetOpts
|
||||||
|
sub: GetOpts
|
||||||
|
data: GetOpts
|
||||||
|
def __init__(self, what: _Optional[str] = ..., desc: _Optional[_Union[GetOpts, _Mapping]] = ..., sub: _Optional[_Union[GetOpts, _Mapping]] = ..., data: _Optional[_Union[GetOpts, _Mapping]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class SetQuery(_message.Message):
|
||||||
|
__slots__ = ["desc", "sub", "tags", "cred", "aux"]
|
||||||
|
class AuxEntry(_message.Message):
|
||||||
|
__slots__ = ["key", "value"]
|
||||||
|
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
key: str
|
||||||
|
value: bytes
|
||||||
|
def __init__(self, key: _Optional[str] = ..., value: _Optional[bytes] = ...) -> None: ...
|
||||||
|
DESC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SUB_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TAGS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
CRED_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
AUX_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
desc: SetDesc
|
||||||
|
sub: SetSub
|
||||||
|
tags: _containers.RepeatedScalarFieldContainer[str]
|
||||||
|
cred: ClientCred
|
||||||
|
aux: _containers.ScalarMap[str, bytes]
|
||||||
|
def __init__(self, desc: _Optional[_Union[SetDesc, _Mapping]] = ..., sub: _Optional[_Union[SetSub, _Mapping]] = ..., tags: _Optional[_Iterable[str]] = ..., cred: _Optional[_Union[ClientCred, _Mapping]] = ..., aux: _Optional[_Mapping[str, bytes]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientHi(_message.Message):
|
||||||
|
__slots__ = ["id", "user_agent", "ver", "device_id", "lang", "platform", "background", "tenant"]
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
USER_AGENT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
VER_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DEVICE_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
LANG_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PLATFORM_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
BACKGROUND_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TENANT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
user_agent: str
|
||||||
|
ver: str
|
||||||
|
device_id: str
|
||||||
|
lang: str
|
||||||
|
platform: str
|
||||||
|
background: bool
|
||||||
|
tenant: str
|
||||||
|
def __init__(self, id: _Optional[str] = ..., user_agent: _Optional[str] = ..., ver: _Optional[str] = ..., device_id: _Optional[str] = ..., lang: _Optional[str] = ..., platform: _Optional[str] = ..., background: bool = ..., tenant: _Optional[str] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientAcc(_message.Message):
|
||||||
|
__slots__ = ["id", "user_id", "scheme", "secret", "login", "tags", "desc", "cred", "token", "state", "auth_level", "tmp_scheme", "tmp_secret"]
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SCHEME_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SECRET_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
LOGIN_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TAGS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DESC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
CRED_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOKEN_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
STATE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
AUTH_LEVEL_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TMP_SCHEME_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TMP_SECRET_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
user_id: str
|
||||||
|
scheme: str
|
||||||
|
secret: bytes
|
||||||
|
login: bool
|
||||||
|
tags: _containers.RepeatedScalarFieldContainer[str]
|
||||||
|
desc: SetDesc
|
||||||
|
cred: _containers.RepeatedCompositeFieldContainer[ClientCred]
|
||||||
|
token: bytes
|
||||||
|
state: str
|
||||||
|
auth_level: AuthLevel
|
||||||
|
tmp_scheme: str
|
||||||
|
tmp_secret: bytes
|
||||||
|
def __init__(self, id: _Optional[str] = ..., user_id: _Optional[str] = ..., scheme: _Optional[str] = ..., secret: _Optional[bytes] = ..., login: bool = ..., tags: _Optional[_Iterable[str]] = ..., desc: _Optional[_Union[SetDesc, _Mapping]] = ..., cred: _Optional[_Iterable[_Union[ClientCred, _Mapping]]] = ..., token: _Optional[bytes] = ..., state: _Optional[str] = ..., auth_level: _Optional[_Union[AuthLevel, str]] = ..., tmp_scheme: _Optional[str] = ..., tmp_secret: _Optional[bytes] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientLogin(_message.Message):
|
||||||
|
__slots__ = ["id", "scheme", "secret", "cred"]
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SCHEME_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SECRET_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
CRED_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
scheme: str
|
||||||
|
secret: bytes
|
||||||
|
cred: _containers.RepeatedCompositeFieldContainer[ClientCred]
|
||||||
|
def __init__(self, id: _Optional[str] = ..., scheme: _Optional[str] = ..., secret: _Optional[bytes] = ..., cred: _Optional[_Iterable[_Union[ClientCred, _Mapping]]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientSub(_message.Message):
|
||||||
|
__slots__ = ["id", "topic", "set_query", "get_query"]
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SET_QUERY_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
GET_QUERY_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
topic: str
|
||||||
|
set_query: SetQuery
|
||||||
|
get_query: GetQuery
|
||||||
|
def __init__(self, id: _Optional[str] = ..., topic: _Optional[str] = ..., set_query: _Optional[_Union[SetQuery, _Mapping]] = ..., get_query: _Optional[_Union[GetQuery, _Mapping]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientLeave(_message.Message):
|
||||||
|
__slots__ = ["id", "topic", "unsub"]
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
UNSUB_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
topic: str
|
||||||
|
unsub: bool
|
||||||
|
def __init__(self, id: _Optional[str] = ..., topic: _Optional[str] = ..., unsub: bool = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientPub(_message.Message):
|
||||||
|
__slots__ = ["id", "topic", "no_echo", "head", "content"]
|
||||||
|
class HeadEntry(_message.Message):
|
||||||
|
__slots__ = ["key", "value"]
|
||||||
|
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
key: str
|
||||||
|
value: bytes
|
||||||
|
def __init__(self, key: _Optional[str] = ..., value: _Optional[bytes] = ...) -> None: ...
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
NO_ECHO_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
HEAD_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
CONTENT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
topic: str
|
||||||
|
no_echo: bool
|
||||||
|
head: _containers.ScalarMap[str, bytes]
|
||||||
|
content: bytes
|
||||||
|
def __init__(self, id: _Optional[str] = ..., topic: _Optional[str] = ..., no_echo: bool = ..., head: _Optional[_Mapping[str, bytes]] = ..., content: _Optional[bytes] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientGet(_message.Message):
|
||||||
|
__slots__ = ["id", "topic", "query"]
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
QUERY_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
topic: str
|
||||||
|
query: GetQuery
|
||||||
|
def __init__(self, id: _Optional[str] = ..., topic: _Optional[str] = ..., query: _Optional[_Union[GetQuery, _Mapping]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientSet(_message.Message):
|
||||||
|
__slots__ = ["id", "topic", "query"]
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
QUERY_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
topic: str
|
||||||
|
query: SetQuery
|
||||||
|
def __init__(self, id: _Optional[str] = ..., topic: _Optional[str] = ..., query: _Optional[_Union[SetQuery, _Mapping]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientDel(_message.Message):
|
||||||
|
__slots__ = ["id", "topic", "what", "del_seq", "user_id", "cred", "hard"]
|
||||||
|
class What(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||||
|
__slots__ = []
|
||||||
|
X0: _ClassVar[ClientDel.What]
|
||||||
|
MSG: _ClassVar[ClientDel.What]
|
||||||
|
TOPIC: _ClassVar[ClientDel.What]
|
||||||
|
SUB: _ClassVar[ClientDel.What]
|
||||||
|
USER: _ClassVar[ClientDel.What]
|
||||||
|
CRED: _ClassVar[ClientDel.What]
|
||||||
|
X0: ClientDel.What
|
||||||
|
MSG: ClientDel.What
|
||||||
|
TOPIC: ClientDel.What
|
||||||
|
SUB: ClientDel.What
|
||||||
|
USER: ClientDel.What
|
||||||
|
CRED: ClientDel.What
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
WHAT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DEL_SEQ_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
CRED_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
HARD_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
topic: str
|
||||||
|
what: ClientDel.What
|
||||||
|
del_seq: _containers.RepeatedCompositeFieldContainer[SeqRange]
|
||||||
|
user_id: str
|
||||||
|
cred: ClientCred
|
||||||
|
hard: bool
|
||||||
|
def __init__(self, id: _Optional[str] = ..., topic: _Optional[str] = ..., what: _Optional[_Union[ClientDel.What, str]] = ..., del_seq: _Optional[_Iterable[_Union[SeqRange, _Mapping]]] = ..., user_id: _Optional[str] = ..., cred: _Optional[_Union[ClientCred, _Mapping]] = ..., hard: bool = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientNote(_message.Message):
|
||||||
|
__slots__ = ["topic", "what", "seq_id", "unread", "event", "payload"]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
WHAT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SEQ_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
UNREAD_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
EVENT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PAYLOAD_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
topic: str
|
||||||
|
what: InfoNote
|
||||||
|
seq_id: int
|
||||||
|
unread: int
|
||||||
|
event: CallEvent
|
||||||
|
payload: bytes
|
||||||
|
def __init__(self, topic: _Optional[str] = ..., what: _Optional[_Union[InfoNote, str]] = ..., seq_id: _Optional[int] = ..., unread: _Optional[int] = ..., event: _Optional[_Union[CallEvent, str]] = ..., payload: _Optional[bytes] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientExtra(_message.Message):
|
||||||
|
__slots__ = ["attachments", "on_behalf_of", "auth_level"]
|
||||||
|
ATTACHMENTS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
ON_BEHALF_OF_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
AUTH_LEVEL_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
attachments: _containers.RepeatedScalarFieldContainer[str]
|
||||||
|
on_behalf_of: str
|
||||||
|
auth_level: AuthLevel
|
||||||
|
def __init__(self, attachments: _Optional[_Iterable[str]] = ..., on_behalf_of: _Optional[str] = ..., auth_level: _Optional[_Union[AuthLevel, str]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientMsg(_message.Message):
|
||||||
|
__slots__ = ["hi", "acc", "login", "sub", "leave", "pub", "get", "set", "note", "extra"]
|
||||||
|
HI_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
ACC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
LOGIN_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SUB_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
LEAVE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PUB_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
GET_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SET_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DEL_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
NOTE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
EXTRA_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
hi: ClientHi
|
||||||
|
acc: ClientAcc
|
||||||
|
login: ClientLogin
|
||||||
|
sub: ClientSub
|
||||||
|
leave: ClientLeave
|
||||||
|
pub: ClientPub
|
||||||
|
get: ClientGet
|
||||||
|
set: ClientSet
|
||||||
|
note: ClientNote
|
||||||
|
extra: ClientExtra
|
||||||
|
def __init__(self, hi: _Optional[_Union[ClientHi, _Mapping]] = ..., acc: _Optional[_Union[ClientAcc, _Mapping]] = ..., login: _Optional[_Union[ClientLogin, _Mapping]] = ..., sub: _Optional[_Union[ClientSub, _Mapping]] = ..., leave: _Optional[_Union[ClientLeave, _Mapping]] = ..., pub: _Optional[_Union[ClientPub, _Mapping]] = ..., get: _Optional[_Union[ClientGet, _Mapping]] = ..., set: _Optional[_Union[ClientSet, _Mapping]] = ..., note: _Optional[_Union[ClientNote, _Mapping]] = ..., extra: _Optional[_Union[ClientExtra, _Mapping]] = ..., **kwargs) -> None: ...
|
||||||
|
|
||||||
|
class ServerCred(_message.Message):
|
||||||
|
__slots__ = ["method", "value", "done"]
|
||||||
|
METHOD_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DONE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
method: str
|
||||||
|
value: str
|
||||||
|
done: bool
|
||||||
|
def __init__(self, method: _Optional[str] = ..., value: _Optional[str] = ..., done: bool = ...) -> None: ...
|
||||||
|
|
||||||
|
class TopicDesc(_message.Message):
|
||||||
|
__slots__ = ["created_at", "updated_at", "touched_at", "defacs", "acs", "seq_id", "read_id", "recv_id", "del_id", "public", "private", "state", "state_at", "trusted", "is_chan", "online", "last_seen_time", "last_seen_user_agent"]
|
||||||
|
CREATED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
UPDATED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOUCHED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DEFACS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
ACS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SEQ_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
READ_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
RECV_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DEL_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PUBLIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PRIVATE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
STATE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
STATE_AT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TRUSTED_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
IS_CHAN_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
ONLINE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
LAST_SEEN_TIME_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
LAST_SEEN_USER_AGENT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
created_at: int
|
||||||
|
updated_at: int
|
||||||
|
touched_at: int
|
||||||
|
defacs: DefaultAcsMode
|
||||||
|
acs: AccessMode
|
||||||
|
seq_id: int
|
||||||
|
read_id: int
|
||||||
|
recv_id: int
|
||||||
|
del_id: int
|
||||||
|
public: bytes
|
||||||
|
private: bytes
|
||||||
|
state: str
|
||||||
|
state_at: int
|
||||||
|
trusted: bytes
|
||||||
|
is_chan: bool
|
||||||
|
online: bool
|
||||||
|
last_seen_time: int
|
||||||
|
last_seen_user_agent: str
|
||||||
|
def __init__(self, created_at: _Optional[int] = ..., updated_at: _Optional[int] = ..., touched_at: _Optional[int] = ..., defacs: _Optional[_Union[DefaultAcsMode, _Mapping]] = ..., acs: _Optional[_Union[AccessMode, _Mapping]] = ..., seq_id: _Optional[int] = ..., read_id: _Optional[int] = ..., recv_id: _Optional[int] = ..., del_id: _Optional[int] = ..., public: _Optional[bytes] = ..., private: _Optional[bytes] = ..., state: _Optional[str] = ..., state_at: _Optional[int] = ..., trusted: _Optional[bytes] = ..., is_chan: bool = ..., online: bool = ..., last_seen_time: _Optional[int] = ..., last_seen_user_agent: _Optional[str] = ...) -> None: ...
|
||||||
|
|
||||||
|
class TopicSub(_message.Message):
|
||||||
|
__slots__ = ["updated_at", "deleted_at", "online", "acs", "read_id", "recv_id", "public", "trusted", "private", "user_id", "topic", "touched_at", "seq_id", "del_id", "last_seen_time", "last_seen_user_agent"]
|
||||||
|
UPDATED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DELETED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
ONLINE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
ACS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
READ_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
RECV_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PUBLIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TRUSTED_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PRIVATE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOUCHED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SEQ_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DEL_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
LAST_SEEN_TIME_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
LAST_SEEN_USER_AGENT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
updated_at: int
|
||||||
|
deleted_at: int
|
||||||
|
online: bool
|
||||||
|
acs: AccessMode
|
||||||
|
read_id: int
|
||||||
|
recv_id: int
|
||||||
|
public: bytes
|
||||||
|
trusted: bytes
|
||||||
|
private: bytes
|
||||||
|
user_id: str
|
||||||
|
topic: str
|
||||||
|
touched_at: int
|
||||||
|
seq_id: int
|
||||||
|
del_id: int
|
||||||
|
last_seen_time: int
|
||||||
|
last_seen_user_agent: str
|
||||||
|
def __init__(self, updated_at: _Optional[int] = ..., deleted_at: _Optional[int] = ..., online: bool = ..., acs: _Optional[_Union[AccessMode, _Mapping]] = ..., read_id: _Optional[int] = ..., recv_id: _Optional[int] = ..., public: _Optional[bytes] = ..., trusted: _Optional[bytes] = ..., private: _Optional[bytes] = ..., user_id: _Optional[str] = ..., topic: _Optional[str] = ..., touched_at: _Optional[int] = ..., seq_id: _Optional[int] = ..., del_id: _Optional[int] = ..., last_seen_time: _Optional[int] = ..., last_seen_user_agent: _Optional[str] = ...) -> None: ...
|
||||||
|
|
||||||
|
class DelValues(_message.Message):
|
||||||
|
__slots__ = ["del_id", "del_seq"]
|
||||||
|
DEL_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DEL_SEQ_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
del_id: int
|
||||||
|
del_seq: _containers.RepeatedCompositeFieldContainer[SeqRange]
|
||||||
|
def __init__(self, del_id: _Optional[int] = ..., del_seq: _Optional[_Iterable[_Union[SeqRange, _Mapping]]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ServerCtrl(_message.Message):
|
||||||
|
__slots__ = ["id", "topic", "code", "text", "params"]
|
||||||
|
class ParamsEntry(_message.Message):
|
||||||
|
__slots__ = ["key", "value"]
|
||||||
|
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
key: str
|
||||||
|
value: bytes
|
||||||
|
def __init__(self, key: _Optional[str] = ..., value: _Optional[bytes] = ...) -> None: ...
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
CODE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TEXT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PARAMS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
topic: str
|
||||||
|
code: int
|
||||||
|
text: str
|
||||||
|
params: _containers.ScalarMap[str, bytes]
|
||||||
|
def __init__(self, id: _Optional[str] = ..., topic: _Optional[str] = ..., code: _Optional[int] = ..., text: _Optional[str] = ..., params: _Optional[_Mapping[str, bytes]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ServerData(_message.Message):
|
||||||
|
__slots__ = ["topic", "from_user_id", "timestamp", "deleted_at", "seq_id", "head", "content"]
|
||||||
|
class HeadEntry(_message.Message):
|
||||||
|
__slots__ = ["key", "value"]
|
||||||
|
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
key: str
|
||||||
|
value: bytes
|
||||||
|
def __init__(self, key: _Optional[str] = ..., value: _Optional[bytes] = ...) -> None: ...
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
FROM_USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DELETED_AT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SEQ_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
HEAD_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
CONTENT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
topic: str
|
||||||
|
from_user_id: str
|
||||||
|
timestamp: int
|
||||||
|
deleted_at: int
|
||||||
|
seq_id: int
|
||||||
|
head: _containers.ScalarMap[str, bytes]
|
||||||
|
content: bytes
|
||||||
|
def __init__(self, topic: _Optional[str] = ..., from_user_id: _Optional[str] = ..., timestamp: _Optional[int] = ..., deleted_at: _Optional[int] = ..., seq_id: _Optional[int] = ..., head: _Optional[_Mapping[str, bytes]] = ..., content: _Optional[bytes] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ServerPres(_message.Message):
|
||||||
|
__slots__ = ["topic", "src", "what", "user_agent", "seq_id", "del_id", "del_seq", "target_user_id", "actor_user_id", "acs"]
|
||||||
|
class What(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||||
|
__slots__ = []
|
||||||
|
X3: _ClassVar[ServerPres.What]
|
||||||
|
ON: _ClassVar[ServerPres.What]
|
||||||
|
OFF: _ClassVar[ServerPres.What]
|
||||||
|
UA: _ClassVar[ServerPres.What]
|
||||||
|
UPD: _ClassVar[ServerPres.What]
|
||||||
|
GONE: _ClassVar[ServerPres.What]
|
||||||
|
ACS: _ClassVar[ServerPres.What]
|
||||||
|
TERM: _ClassVar[ServerPres.What]
|
||||||
|
MSG: _ClassVar[ServerPres.What]
|
||||||
|
READ: _ClassVar[ServerPres.What]
|
||||||
|
RECV: _ClassVar[ServerPres.What]
|
||||||
|
DEL: _ClassVar[ServerPres.What]
|
||||||
|
TAGS: _ClassVar[ServerPres.What]
|
||||||
|
AUX: _ClassVar[ServerPres.What]
|
||||||
|
X3: ServerPres.What
|
||||||
|
ON: ServerPres.What
|
||||||
|
OFF: ServerPres.What
|
||||||
|
UA: ServerPres.What
|
||||||
|
UPD: ServerPres.What
|
||||||
|
GONE: ServerPres.What
|
||||||
|
ACS: ServerPres.What
|
||||||
|
TERM: ServerPres.What
|
||||||
|
MSG: ServerPres.What
|
||||||
|
READ: ServerPres.What
|
||||||
|
RECV: ServerPres.What
|
||||||
|
DEL: ServerPres.What
|
||||||
|
TAGS: ServerPres.What
|
||||||
|
AUX: ServerPres.What
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SRC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
WHAT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
USER_AGENT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SEQ_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DEL_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DEL_SEQ_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TARGET_USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
ACTOR_USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
ACS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
topic: str
|
||||||
|
src: str
|
||||||
|
what: ServerPres.What
|
||||||
|
user_agent: str
|
||||||
|
seq_id: int
|
||||||
|
del_id: int
|
||||||
|
del_seq: _containers.RepeatedCompositeFieldContainer[SeqRange]
|
||||||
|
target_user_id: str
|
||||||
|
actor_user_id: str
|
||||||
|
acs: AccessMode
|
||||||
|
def __init__(self, topic: _Optional[str] = ..., src: _Optional[str] = ..., what: _Optional[_Union[ServerPres.What, str]] = ..., user_agent: _Optional[str] = ..., seq_id: _Optional[int] = ..., del_id: _Optional[int] = ..., del_seq: _Optional[_Iterable[_Union[SeqRange, _Mapping]]] = ..., target_user_id: _Optional[str] = ..., actor_user_id: _Optional[str] = ..., acs: _Optional[_Union[AccessMode, _Mapping]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ServerMeta(_message.Message):
|
||||||
|
__slots__ = ["id", "topic", "desc", "sub", "tags", "cred", "aux"]
|
||||||
|
class AuxEntry(_message.Message):
|
||||||
|
__slots__ = ["key", "value"]
|
||||||
|
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
key: str
|
||||||
|
value: bytes
|
||||||
|
def __init__(self, key: _Optional[str] = ..., value: _Optional[bytes] = ...) -> None: ...
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DESC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SUB_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DEL_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TAGS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
CRED_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
AUX_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
topic: str
|
||||||
|
desc: TopicDesc
|
||||||
|
sub: _containers.RepeatedCompositeFieldContainer[TopicSub]
|
||||||
|
tags: _containers.RepeatedScalarFieldContainer[str]
|
||||||
|
cred: _containers.RepeatedCompositeFieldContainer[ServerCred]
|
||||||
|
aux: _containers.ScalarMap[str, bytes]
|
||||||
|
def __init__(self, id: _Optional[str] = ..., topic: _Optional[str] = ..., desc: _Optional[_Union[TopicDesc, _Mapping]] = ..., sub: _Optional[_Iterable[_Union[TopicSub, _Mapping]]] = ..., tags: _Optional[_Iterable[str]] = ..., cred: _Optional[_Iterable[_Union[ServerCred, _Mapping]]] = ..., aux: _Optional[_Mapping[str, bytes]] = ..., **kwargs) -> None: ...
|
||||||
|
|
||||||
|
class ServerInfo(_message.Message):
|
||||||
|
__slots__ = ["topic", "from_user_id", "what", "seq_id", "src", "event", "payload"]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
FROM_USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
WHAT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SEQ_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SRC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
EVENT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PAYLOAD_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
topic: str
|
||||||
|
from_user_id: str
|
||||||
|
what: InfoNote
|
||||||
|
seq_id: int
|
||||||
|
src: str
|
||||||
|
event: CallEvent
|
||||||
|
payload: bytes
|
||||||
|
def __init__(self, topic: _Optional[str] = ..., from_user_id: _Optional[str] = ..., what: _Optional[_Union[InfoNote, str]] = ..., seq_id: _Optional[int] = ..., src: _Optional[str] = ..., event: _Optional[_Union[CallEvent, str]] = ..., payload: _Optional[bytes] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ServerMsg(_message.Message):
|
||||||
|
__slots__ = ["ctrl", "data", "pres", "meta", "info", "topic"]
|
||||||
|
CTRL_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DATA_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PRES_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
META_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
INFO_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
ctrl: ServerCtrl
|
||||||
|
data: ServerData
|
||||||
|
pres: ServerPres
|
||||||
|
meta: ServerMeta
|
||||||
|
info: ServerInfo
|
||||||
|
topic: str
|
||||||
|
def __init__(self, ctrl: _Optional[_Union[ServerCtrl, _Mapping]] = ..., data: _Optional[_Union[ServerData, _Mapping]] = ..., pres: _Optional[_Union[ServerPres, _Mapping]] = ..., meta: _Optional[_Union[ServerMeta, _Mapping]] = ..., info: _Optional[_Union[ServerInfo, _Mapping]] = ..., topic: _Optional[str] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ServerResp(_message.Message):
|
||||||
|
__slots__ = ["status", "srvmsg", "clmsg"]
|
||||||
|
STATUS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SRVMSG_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
CLMSG_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
status: RespCode
|
||||||
|
srvmsg: ServerMsg
|
||||||
|
clmsg: ClientMsg
|
||||||
|
def __init__(self, status: _Optional[_Union[RespCode, str]] = ..., srvmsg: _Optional[_Union[ServerMsg, _Mapping]] = ..., clmsg: _Optional[_Union[ClientMsg, _Mapping]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class Session(_message.Message):
|
||||||
|
__slots__ = ["session_id", "user_id", "auth_level", "remote_addr", "user_agent", "device_id", "language"]
|
||||||
|
SESSION_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
AUTH_LEVEL_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
REMOTE_ADDR_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
USER_AGENT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DEVICE_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
LANGUAGE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
session_id: str
|
||||||
|
user_id: str
|
||||||
|
auth_level: AuthLevel
|
||||||
|
remote_addr: str
|
||||||
|
user_agent: str
|
||||||
|
device_id: str
|
||||||
|
language: str
|
||||||
|
def __init__(self, session_id: _Optional[str] = ..., user_id: _Optional[str] = ..., auth_level: _Optional[_Union[AuthLevel, str]] = ..., remote_addr: _Optional[str] = ..., user_agent: _Optional[str] = ..., device_id: _Optional[str] = ..., language: _Optional[str] = ...) -> None: ...
|
||||||
|
|
||||||
|
class ClientReq(_message.Message):
|
||||||
|
__slots__ = ["msg", "sess"]
|
||||||
|
MSG_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SESS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
msg: ClientMsg
|
||||||
|
sess: Session
|
||||||
|
def __init__(self, msg: _Optional[_Union[ClientMsg, _Mapping]] = ..., sess: _Optional[_Union[Session, _Mapping]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class SearchQuery(_message.Message):
|
||||||
|
__slots__ = ["user_id", "query"]
|
||||||
|
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
QUERY_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
user_id: str
|
||||||
|
query: str
|
||||||
|
def __init__(self, user_id: _Optional[str] = ..., query: _Optional[str] = ...) -> None: ...
|
||||||
|
|
||||||
|
class SearchFound(_message.Message):
|
||||||
|
__slots__ = ["status", "query", "result"]
|
||||||
|
STATUS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
QUERY_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
RESULT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
status: RespCode
|
||||||
|
query: str
|
||||||
|
result: _containers.RepeatedCompositeFieldContainer[TopicSub]
|
||||||
|
def __init__(self, status: _Optional[_Union[RespCode, str]] = ..., query: _Optional[str] = ..., result: _Optional[_Iterable[_Union[TopicSub, _Mapping]]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class TopicEvent(_message.Message):
|
||||||
|
__slots__ = ["action", "name", "desc"]
|
||||||
|
ACTION_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DESC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
action: Crud
|
||||||
|
name: str
|
||||||
|
desc: TopicDesc
|
||||||
|
def __init__(self, action: _Optional[_Union[Crud, str]] = ..., name: _Optional[str] = ..., desc: _Optional[_Union[TopicDesc, _Mapping]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class AccountEvent(_message.Message):
|
||||||
|
__slots__ = ["action", "user_id", "default_acs", "public", "tags"]
|
||||||
|
ACTION_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DEFAULT_ACS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PUBLIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TAGS_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
action: Crud
|
||||||
|
user_id: str
|
||||||
|
default_acs: DefaultAcsMode
|
||||||
|
public: bytes
|
||||||
|
tags: _containers.RepeatedScalarFieldContainer[str]
|
||||||
|
def __init__(self, action: _Optional[_Union[Crud, str]] = ..., user_id: _Optional[str] = ..., default_acs: _Optional[_Union[DefaultAcsMode, _Mapping]] = ..., public: _Optional[bytes] = ..., tags: _Optional[_Iterable[str]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class SubscriptionEvent(_message.Message):
|
||||||
|
__slots__ = ["action", "topic", "user_id", "del_id", "read_id", "recv_id", "mode", "private"]
|
||||||
|
ACTION_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
DEL_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
READ_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
RECV_ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
MODE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
PRIVATE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
action: Crud
|
||||||
|
topic: str
|
||||||
|
user_id: str
|
||||||
|
del_id: int
|
||||||
|
read_id: int
|
||||||
|
recv_id: int
|
||||||
|
mode: AccessMode
|
||||||
|
private: bytes
|
||||||
|
def __init__(self, action: _Optional[_Union[Crud, str]] = ..., topic: _Optional[str] = ..., user_id: _Optional[str] = ..., del_id: _Optional[int] = ..., read_id: _Optional[int] = ..., recv_id: _Optional[int] = ..., mode: _Optional[_Union[AccessMode, _Mapping]] = ..., private: _Optional[bytes] = ...) -> None: ...
|
||||||
|
|
||||||
|
class MessageEvent(_message.Message):
|
||||||
|
__slots__ = ["action", "msg"]
|
||||||
|
ACTION_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
MSG_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
action: Crud
|
||||||
|
msg: ServerData
|
||||||
|
def __init__(self, action: _Optional[_Union[Crud, str]] = ..., msg: _Optional[_Union[ServerData, _Mapping]] = ...) -> None: ...
|
||||||
|
|
||||||
|
class Auth(_message.Message):
|
||||||
|
__slots__ = ["scheme", "secret"]
|
||||||
|
SCHEME_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SECRET_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
scheme: str
|
||||||
|
secret: str
|
||||||
|
def __init__(self, scheme: _Optional[str] = ..., secret: _Optional[str] = ...) -> None: ...
|
||||||
|
|
||||||
|
class FileMeta(_message.Message):
|
||||||
|
__slots__ = ["name", "mime_type", "etag", "size"]
|
||||||
|
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
MIME_TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
ETAG_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
SIZE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
name: str
|
||||||
|
mime_type: str
|
||||||
|
etag: str
|
||||||
|
size: int
|
||||||
|
def __init__(self, name: _Optional[str] = ..., mime_type: _Optional[str] = ..., etag: _Optional[str] = ..., size: _Optional[int] = ...) -> None: ...
|
||||||
|
|
||||||
|
class FileUpReq(_message.Message):
|
||||||
|
__slots__ = ["id", "auth", "topic", "meta", "content"]
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
AUTH_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
META_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
CONTENT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
auth: Auth
|
||||||
|
topic: str
|
||||||
|
meta: FileMeta
|
||||||
|
content: bytes
|
||||||
|
def __init__(self, id: _Optional[str] = ..., auth: _Optional[_Union[Auth, _Mapping]] = ..., topic: _Optional[str] = ..., meta: _Optional[_Union[FileMeta, _Mapping]] = ..., content: _Optional[bytes] = ...) -> None: ...
|
||||||
|
|
||||||
|
class FileUpResp(_message.Message):
|
||||||
|
__slots__ = ["id", "code", "text", "meta", "redir_url"]
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
CODE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TEXT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
META_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
REDIR_URL_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
code: int
|
||||||
|
text: str
|
||||||
|
meta: FileMeta
|
||||||
|
redir_url: str
|
||||||
|
def __init__(self, id: _Optional[str] = ..., code: _Optional[int] = ..., text: _Optional[str] = ..., meta: _Optional[_Union[FileMeta, _Mapping]] = ..., redir_url: _Optional[str] = ...) -> None: ...
|
||||||
|
|
||||||
|
class FileDownReq(_message.Message):
|
||||||
|
__slots__ = ["id", "auth", "uri", "if_modified"]
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
AUTH_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
URI_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
IF_MODIFIED_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
auth: Auth
|
||||||
|
uri: str
|
||||||
|
if_modified: str
|
||||||
|
def __init__(self, id: _Optional[str] = ..., auth: _Optional[_Union[Auth, _Mapping]] = ..., uri: _Optional[str] = ..., if_modified: _Optional[str] = ...) -> None: ...
|
||||||
|
|
||||||
|
class FileDownResp(_message.Message):
|
||||||
|
__slots__ = ["id", "code", "text", "meta", "redir_url", "content"]
|
||||||
|
ID_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
CODE_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
TEXT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
META_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
REDIR_URL_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
CONTENT_FIELD_NUMBER: _ClassVar[int]
|
||||||
|
id: str
|
||||||
|
code: int
|
||||||
|
text: str
|
||||||
|
meta: FileMeta
|
||||||
|
redir_url: str
|
||||||
|
content: bytes
|
||||||
|
def __init__(self, id: _Optional[str] = ..., code: _Optional[int] = ..., text: _Optional[str] = ..., meta: _Optional[_Union[FileMeta, _Mapping]] = ..., redir_url: _Optional[str] = ..., content: _Optional[bytes] = ...) -> None: ...
|
||||||
|
|||||||
@@ -0,0 +1,378 @@
|
|||||||
|
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
||||||
|
"""Client and server classes corresponding to protobuf-defined services."""
|
||||||
|
import grpc
|
||||||
|
|
||||||
|
from . import model_pb2 as model__pb2
|
||||||
|
|
||||||
|
|
||||||
|
class NodeStub(object):
|
||||||
|
"""This is the methods that needs to be implemented by a gRPC client.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, channel):
|
||||||
|
"""Constructor.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
channel: A grpc.Channel.
|
||||||
|
"""
|
||||||
|
self.MessageLoop = channel.stream_stream(
|
||||||
|
'/pbx.Node/MessageLoop',
|
||||||
|
request_serializer=model__pb2.ClientMsg.SerializeToString,
|
||||||
|
response_deserializer=model__pb2.ServerMsg.FromString,
|
||||||
|
)
|
||||||
|
self.LargeFileReceive = channel.stream_unary(
|
||||||
|
'/pbx.Node/LargeFileReceive',
|
||||||
|
request_serializer=model__pb2.FileUpReq.SerializeToString,
|
||||||
|
response_deserializer=model__pb2.FileUpResp.FromString,
|
||||||
|
)
|
||||||
|
self.LargeFileServe = channel.unary_stream(
|
||||||
|
'/pbx.Node/LargeFileServe',
|
||||||
|
request_serializer=model__pb2.FileDownReq.SerializeToString,
|
||||||
|
response_deserializer=model__pb2.FileDownResp.FromString,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class NodeServicer(object):
|
||||||
|
"""This is the methods that needs to be implemented by a gRPC client.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def MessageLoop(self, request_iterator, context):
|
||||||
|
"""Client sends a stream of ClientMsg, server responds with a stream of ServerMsg
|
||||||
|
"""
|
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
|
context.set_details('Method not implemented!')
|
||||||
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
|
def LargeFileReceive(self, request_iterator, context):
|
||||||
|
"""Large file upload: a request with a stream of chunks.
|
||||||
|
"""
|
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
|
context.set_details('Method not implemented!')
|
||||||
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
|
def LargeFileServe(self, request, context):
|
||||||
|
"""Large file file download: a response with a stream of chunks.
|
||||||
|
"""
|
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
|
context.set_details('Method not implemented!')
|
||||||
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
|
|
||||||
|
def add_NodeServicer_to_server(servicer, server):
|
||||||
|
rpc_method_handlers = {
|
||||||
|
'MessageLoop': grpc.stream_stream_rpc_method_handler(
|
||||||
|
servicer.MessageLoop,
|
||||||
|
request_deserializer=model__pb2.ClientMsg.FromString,
|
||||||
|
response_serializer=model__pb2.ServerMsg.SerializeToString,
|
||||||
|
),
|
||||||
|
'LargeFileReceive': grpc.stream_unary_rpc_method_handler(
|
||||||
|
servicer.LargeFileReceive,
|
||||||
|
request_deserializer=model__pb2.FileUpReq.FromString,
|
||||||
|
response_serializer=model__pb2.FileUpResp.SerializeToString,
|
||||||
|
),
|
||||||
|
'LargeFileServe': grpc.unary_stream_rpc_method_handler(
|
||||||
|
servicer.LargeFileServe,
|
||||||
|
request_deserializer=model__pb2.FileDownReq.FromString,
|
||||||
|
response_serializer=model__pb2.FileDownResp.SerializeToString,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
generic_handler = grpc.method_handlers_generic_handler(
|
||||||
|
'pbx.Node', rpc_method_handlers)
|
||||||
|
server.add_generic_rpc_handlers((generic_handler,))
|
||||||
|
|
||||||
|
|
||||||
|
# This class is part of an EXPERIMENTAL API.
|
||||||
|
class Node(object):
|
||||||
|
"""This is the methods that needs to be implemented by a gRPC client.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def MessageLoop(request_iterator,
|
||||||
|
target,
|
||||||
|
options=(),
|
||||||
|
channel_credentials=None,
|
||||||
|
call_credentials=None,
|
||||||
|
insecure=False,
|
||||||
|
compression=None,
|
||||||
|
wait_for_ready=None,
|
||||||
|
timeout=None,
|
||||||
|
metadata=None):
|
||||||
|
return grpc.experimental.stream_stream(request_iterator, target, '/pbx.Node/MessageLoop',
|
||||||
|
model__pb2.ClientMsg.SerializeToString,
|
||||||
|
model__pb2.ServerMsg.FromString,
|
||||||
|
options, channel_credentials,
|
||||||
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def LargeFileReceive(request_iterator,
|
||||||
|
target,
|
||||||
|
options=(),
|
||||||
|
channel_credentials=None,
|
||||||
|
call_credentials=None,
|
||||||
|
insecure=False,
|
||||||
|
compression=None,
|
||||||
|
wait_for_ready=None,
|
||||||
|
timeout=None,
|
||||||
|
metadata=None):
|
||||||
|
return grpc.experimental.stream_unary(request_iterator, target, '/pbx.Node/LargeFileReceive',
|
||||||
|
model__pb2.FileUpReq.SerializeToString,
|
||||||
|
model__pb2.FileUpResp.FromString,
|
||||||
|
options, channel_credentials,
|
||||||
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def LargeFileServe(request,
|
||||||
|
target,
|
||||||
|
options=(),
|
||||||
|
channel_credentials=None,
|
||||||
|
call_credentials=None,
|
||||||
|
insecure=False,
|
||||||
|
compression=None,
|
||||||
|
wait_for_ready=None,
|
||||||
|
timeout=None,
|
||||||
|
metadata=None):
|
||||||
|
return grpc.experimental.unary_stream(request, target, '/pbx.Node/LargeFileServe',
|
||||||
|
model__pb2.FileDownReq.SerializeToString,
|
||||||
|
model__pb2.FileDownResp.FromString,
|
||||||
|
options, channel_credentials,
|
||||||
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||||
|
|
||||||
|
|
||||||
|
class PluginStub(object):
|
||||||
|
"""Plugin interface.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, channel):
|
||||||
|
"""Constructor.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
channel: A grpc.Channel.
|
||||||
|
"""
|
||||||
|
self.FireHose = channel.unary_unary(
|
||||||
|
'/pbx.Plugin/FireHose',
|
||||||
|
request_serializer=model__pb2.ClientReq.SerializeToString,
|
||||||
|
response_deserializer=model__pb2.ServerResp.FromString,
|
||||||
|
)
|
||||||
|
self.Find = channel.unary_unary(
|
||||||
|
'/pbx.Plugin/Find',
|
||||||
|
request_serializer=model__pb2.SearchQuery.SerializeToString,
|
||||||
|
response_deserializer=model__pb2.SearchFound.FromString,
|
||||||
|
)
|
||||||
|
self.Account = channel.unary_unary(
|
||||||
|
'/pbx.Plugin/Account',
|
||||||
|
request_serializer=model__pb2.AccountEvent.SerializeToString,
|
||||||
|
response_deserializer=model__pb2.Unused.FromString,
|
||||||
|
)
|
||||||
|
self.Topic = channel.unary_unary(
|
||||||
|
'/pbx.Plugin/Topic',
|
||||||
|
request_serializer=model__pb2.TopicEvent.SerializeToString,
|
||||||
|
response_deserializer=model__pb2.Unused.FromString,
|
||||||
|
)
|
||||||
|
self.Subscription = channel.unary_unary(
|
||||||
|
'/pbx.Plugin/Subscription',
|
||||||
|
request_serializer=model__pb2.SubscriptionEvent.SerializeToString,
|
||||||
|
response_deserializer=model__pb2.Unused.FromString,
|
||||||
|
)
|
||||||
|
self.Message = channel.unary_unary(
|
||||||
|
'/pbx.Plugin/Message',
|
||||||
|
request_serializer=model__pb2.MessageEvent.SerializeToString,
|
||||||
|
response_deserializer=model__pb2.Unused.FromString,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PluginServicer(object):
|
||||||
|
"""Plugin interface.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def FireHose(self, request, context):
|
||||||
|
"""This plugin method is called by Tinode server for every message received from the clients. The
|
||||||
|
method returns a ServerResp message. ServerResp.status tells Tinode server what to do next.
|
||||||
|
See possible values for ServerResp.status in RespCode below.
|
||||||
|
"""
|
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
|
context.set_details('Method not implemented!')
|
||||||
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
|
def Find(self, request, context):
|
||||||
|
"""An alteranative user and topic discovery mechanism.
|
||||||
|
A search request issued on a 'fnd' topic. This method is called to generate an alternative result set.
|
||||||
|
"""
|
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
|
context.set_details('Method not implemented!')
|
||||||
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
|
def Account(self, request, context):
|
||||||
|
"""The following methods are for the Tinode server to report individual events.
|
||||||
|
|
||||||
|
Account created, updated or deleted
|
||||||
|
"""
|
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
|
context.set_details('Method not implemented!')
|
||||||
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
|
def Topic(self, request, context):
|
||||||
|
"""Topic created, updated [or deleted -- not supported yet]
|
||||||
|
"""
|
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
|
context.set_details('Method not implemented!')
|
||||||
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
|
def Subscription(self, request, context):
|
||||||
|
"""Subscription created, updated or deleted
|
||||||
|
"""
|
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
|
context.set_details('Method not implemented!')
|
||||||
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
|
def Message(self, request, context):
|
||||||
|
"""Message published or deleted
|
||||||
|
"""
|
||||||
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||||
|
context.set_details('Method not implemented!')
|
||||||
|
raise NotImplementedError('Method not implemented!')
|
||||||
|
|
||||||
|
|
||||||
|
def add_PluginServicer_to_server(servicer, server):
|
||||||
|
rpc_method_handlers = {
|
||||||
|
'FireHose': grpc.unary_unary_rpc_method_handler(
|
||||||
|
servicer.FireHose,
|
||||||
|
request_deserializer=model__pb2.ClientReq.FromString,
|
||||||
|
response_serializer=model__pb2.ServerResp.SerializeToString,
|
||||||
|
),
|
||||||
|
'Find': grpc.unary_unary_rpc_method_handler(
|
||||||
|
servicer.Find,
|
||||||
|
request_deserializer=model__pb2.SearchQuery.FromString,
|
||||||
|
response_serializer=model__pb2.SearchFound.SerializeToString,
|
||||||
|
),
|
||||||
|
'Account': grpc.unary_unary_rpc_method_handler(
|
||||||
|
servicer.Account,
|
||||||
|
request_deserializer=model__pb2.AccountEvent.FromString,
|
||||||
|
response_serializer=model__pb2.Unused.SerializeToString,
|
||||||
|
),
|
||||||
|
'Topic': grpc.unary_unary_rpc_method_handler(
|
||||||
|
servicer.Topic,
|
||||||
|
request_deserializer=model__pb2.TopicEvent.FromString,
|
||||||
|
response_serializer=model__pb2.Unused.SerializeToString,
|
||||||
|
),
|
||||||
|
'Subscription': grpc.unary_unary_rpc_method_handler(
|
||||||
|
servicer.Subscription,
|
||||||
|
request_deserializer=model__pb2.SubscriptionEvent.FromString,
|
||||||
|
response_serializer=model__pb2.Unused.SerializeToString,
|
||||||
|
),
|
||||||
|
'Message': grpc.unary_unary_rpc_method_handler(
|
||||||
|
servicer.Message,
|
||||||
|
request_deserializer=model__pb2.MessageEvent.FromString,
|
||||||
|
response_serializer=model__pb2.Unused.SerializeToString,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
generic_handler = grpc.method_handlers_generic_handler(
|
||||||
|
'pbx.Plugin', rpc_method_handlers)
|
||||||
|
server.add_generic_rpc_handlers((generic_handler,))
|
||||||
|
|
||||||
|
|
||||||
|
# This class is part of an EXPERIMENTAL API.
|
||||||
|
class Plugin(object):
|
||||||
|
"""Plugin interface.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def FireHose(request,
|
||||||
|
target,
|
||||||
|
options=(),
|
||||||
|
channel_credentials=None,
|
||||||
|
call_credentials=None,
|
||||||
|
insecure=False,
|
||||||
|
compression=None,
|
||||||
|
wait_for_ready=None,
|
||||||
|
timeout=None,
|
||||||
|
metadata=None):
|
||||||
|
return grpc.experimental.unary_unary(request, target, '/pbx.Plugin/FireHose',
|
||||||
|
model__pb2.ClientReq.SerializeToString,
|
||||||
|
model__pb2.ServerResp.FromString,
|
||||||
|
options, channel_credentials,
|
||||||
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def Find(request,
|
||||||
|
target,
|
||||||
|
options=(),
|
||||||
|
channel_credentials=None,
|
||||||
|
call_credentials=None,
|
||||||
|
insecure=False,
|
||||||
|
compression=None,
|
||||||
|
wait_for_ready=None,
|
||||||
|
timeout=None,
|
||||||
|
metadata=None):
|
||||||
|
return grpc.experimental.unary_unary(request, target, '/pbx.Plugin/Find',
|
||||||
|
model__pb2.SearchQuery.SerializeToString,
|
||||||
|
model__pb2.SearchFound.FromString,
|
||||||
|
options, channel_credentials,
|
||||||
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def Account(request,
|
||||||
|
target,
|
||||||
|
options=(),
|
||||||
|
channel_credentials=None,
|
||||||
|
call_credentials=None,
|
||||||
|
insecure=False,
|
||||||
|
compression=None,
|
||||||
|
wait_for_ready=None,
|
||||||
|
timeout=None,
|
||||||
|
metadata=None):
|
||||||
|
return grpc.experimental.unary_unary(request, target, '/pbx.Plugin/Account',
|
||||||
|
model__pb2.AccountEvent.SerializeToString,
|
||||||
|
model__pb2.Unused.FromString,
|
||||||
|
options, channel_credentials,
|
||||||
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def Topic(request,
|
||||||
|
target,
|
||||||
|
options=(),
|
||||||
|
channel_credentials=None,
|
||||||
|
call_credentials=None,
|
||||||
|
insecure=False,
|
||||||
|
compression=None,
|
||||||
|
wait_for_ready=None,
|
||||||
|
timeout=None,
|
||||||
|
metadata=None):
|
||||||
|
return grpc.experimental.unary_unary(request, target, '/pbx.Plugin/Topic',
|
||||||
|
model__pb2.TopicEvent.SerializeToString,
|
||||||
|
model__pb2.Unused.FromString,
|
||||||
|
options, channel_credentials,
|
||||||
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def Subscription(request,
|
||||||
|
target,
|
||||||
|
options=(),
|
||||||
|
channel_credentials=None,
|
||||||
|
call_credentials=None,
|
||||||
|
insecure=False,
|
||||||
|
compression=None,
|
||||||
|
wait_for_ready=None,
|
||||||
|
timeout=None,
|
||||||
|
metadata=None):
|
||||||
|
return grpc.experimental.unary_unary(request, target, '/pbx.Plugin/Subscription',
|
||||||
|
model__pb2.SubscriptionEvent.SerializeToString,
|
||||||
|
model__pb2.Unused.FromString,
|
||||||
|
options, channel_credentials,
|
||||||
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def Message(request,
|
||||||
|
target,
|
||||||
|
options=(),
|
||||||
|
channel_credentials=None,
|
||||||
|
call_credentials=None,
|
||||||
|
insecure=False,
|
||||||
|
compression=None,
|
||||||
|
wait_for_ready=None,
|
||||||
|
timeout=None,
|
||||||
|
metadata=None):
|
||||||
|
return grpc.experimental.unary_unary(request, target, '/pbx.Plugin/Message',
|
||||||
|
model__pb2.MessageEvent.SerializeToString,
|
||||||
|
model__pb2.Unused.FromString,
|
||||||
|
options, channel_credentials,
|
||||||
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||||
|
|||||||
Reference in New Issue
Block a user