Live: simplify dependencies (#115130)
This commit is contained in:
+8
-6
@@ -377,10 +377,10 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/centrifugal/centrifuge v0.37.2 h1:rerQNvDfYN2FZEkVtb/hvGV7SIrJfEQrKF3MaE8GDlo=
|
||||
github.com/centrifugal/centrifuge v0.37.2/go.mod h1:aj4iRJGhzi3SlL8iUtVezxway1Xf8g+hmNQkLLO7sS8=
|
||||
github.com/centrifugal/protocol v0.16.2 h1:KoIHgDeX1fFxyxQoKW+6E8ZTCf5mwGm8JyGoJ5NBMbQ=
|
||||
github.com/centrifugal/protocol v0.16.2/go.mod h1:Q7OpS/8HMXDnL7f9DpNx24IhG96MP88WPpVTTCdrokI=
|
||||
github.com/centrifugal/centrifuge v0.38.0 h1:UJTowwc5lSwnpvd3vbrTseODbU7osSggN67RTrJ8EfQ=
|
||||
github.com/centrifugal/centrifuge v0.38.0/go.mod h1:rcZLARnO5GXOeE9qG7iIPMvERxESespqkSX4cGLCAzo=
|
||||
github.com/centrifugal/protocol v0.17.0 h1:hD0WczyiG7zrVJcgkQsd5/nhfFXt0Y04SJHV2Z7B1rg=
|
||||
github.com/centrifugal/protocol v0.17.0/go.mod h1:9MdiYyjw5Bw1+d5Sp4Y0NK+qiuTNyd88nrHJsUUh8k4=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
@@ -1376,11 +1376,13 @@ github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9p
|
||||
github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU=
|
||||
github.com/puzpuzpuz/xsync/v4 v4.2.0 h1:dlxm77dZj2c3rxq0/XNvvUKISAmovoXF4a4qM6Wvkr0=
|
||||
github.com/puzpuzpuz/xsync/v4 v4.2.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
|
||||
github.com/quagmt/udecimal v1.9.0 h1:TLuZiFeg0HhS6X8VDa78Y6XTaitZZfh+z5q4SXMzpDQ=
|
||||
github.com/quagmt/udecimal v1.9.0/go.mod h1:ScmJ/xTGZcEoYiyMMzgDLn79PEJHcMBiJ4NNRT3FirA=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/redis/go-redis/v9 v9.14.0 h1:u4tNCjXOyzfgeLN+vAZaW1xUooqWDqVEsZN0U01jfAE=
|
||||
github.com/redis/go-redis/v9 v9.14.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
||||
github.com/redis/rueidis v1.0.64 h1:XqgbueDuNV3qFdVdQwAHJl1uNt90zUuAJuzqjH4cw6Y=
|
||||
github.com/redis/rueidis v1.0.64/go.mod h1:Lkhr2QTgcoYBhxARU7kJRO8SyVlgUuEkcJO1Y8MCluA=
|
||||
github.com/redis/rueidis v1.0.68 h1:gept0E45JGxVigWb3zoWHvxEc4IOC7kc4V/4XvN8eG8=
|
||||
github.com/redis/rueidis v1.0.68/go.mod h1:Lkhr2QTgcoYBhxARU7kJRO8SyVlgUuEkcJO1Y8MCluA=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
|
||||
@@ -48,7 +48,7 @@ require (
|
||||
github.com/blugelabs/bluge_segment_api v0.2.0 // @grafana/grafana-backend-group
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // @grafana/grafana-backend-group
|
||||
github.com/bwmarrin/snowflake v0.3.0 // @grafana/grafana-app-platform-squad
|
||||
github.com/centrifugal/centrifuge v0.37.2 // @grafana/grafana-app-platform-squad
|
||||
github.com/centrifugal/centrifuge v0.38.0 // @grafana/grafana-app-platform-squad
|
||||
github.com/crewjam/saml v0.4.14 // @grafana/identity-access-team
|
||||
github.com/dgraph-io/badger/v4 v4.7.0 // @grafana/grafana-search-and-storage
|
||||
github.com/dlmiddlecote/sqlstats v1.0.2 // @grafana/grafana-backend-group
|
||||
@@ -386,7 +386,7 @@ require (
|
||||
github.com/caio/go-tdigest v3.1.0+incompatible // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // @grafana/alerting-backend
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/centrifugal/protocol v0.16.2 // indirect
|
||||
github.com/centrifugal/protocol v0.17.0 // indirect
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cheekybits/genny v1.0.0 // indirect
|
||||
@@ -562,7 +562,7 @@ require (
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d // indirect
|
||||
github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect
|
||||
github.com/redis/rueidis v1.0.64 // indirect
|
||||
github.com/redis/rueidis v1.0.68 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
@@ -687,6 +687,7 @@ require (
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/quagmt/udecimal v1.9.0 // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.25.3 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||
github.com/tklauser/numcpus v0.8.0 // indirect
|
||||
|
||||
@@ -1006,10 +1006,10 @@ github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F9
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
|
||||
github.com/centrifugal/centrifuge v0.37.2 h1:rerQNvDfYN2FZEkVtb/hvGV7SIrJfEQrKF3MaE8GDlo=
|
||||
github.com/centrifugal/centrifuge v0.37.2/go.mod h1:aj4iRJGhzi3SlL8iUtVezxway1Xf8g+hmNQkLLO7sS8=
|
||||
github.com/centrifugal/protocol v0.16.2 h1:KoIHgDeX1fFxyxQoKW+6E8ZTCf5mwGm8JyGoJ5NBMbQ=
|
||||
github.com/centrifugal/protocol v0.16.2/go.mod h1:Q7OpS/8HMXDnL7f9DpNx24IhG96MP88WPpVTTCdrokI=
|
||||
github.com/centrifugal/centrifuge v0.38.0 h1:UJTowwc5lSwnpvd3vbrTseODbU7osSggN67RTrJ8EfQ=
|
||||
github.com/centrifugal/centrifuge v0.38.0/go.mod h1:rcZLARnO5GXOeE9qG7iIPMvERxESespqkSX4cGLCAzo=
|
||||
github.com/centrifugal/protocol v0.17.0 h1:hD0WczyiG7zrVJcgkQsd5/nhfFXt0Y04SJHV2Z7B1rg=
|
||||
github.com/centrifugal/protocol v0.17.0/go.mod h1:9MdiYyjw5Bw1+d5Sp4Y0NK+qiuTNyd88nrHJsUUh8k4=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
@@ -2334,11 +2334,13 @@ github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9p
|
||||
github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU=
|
||||
github.com/puzpuzpuz/xsync/v4 v4.2.0 h1:dlxm77dZj2c3rxq0/XNvvUKISAmovoXF4a4qM6Wvkr0=
|
||||
github.com/puzpuzpuz/xsync/v4 v4.2.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
|
||||
github.com/quagmt/udecimal v1.9.0 h1:TLuZiFeg0HhS6X8VDa78Y6XTaitZZfh+z5q4SXMzpDQ=
|
||||
github.com/quagmt/udecimal v1.9.0/go.mod h1:ScmJ/xTGZcEoYiyMMzgDLn79PEJHcMBiJ4NNRT3FirA=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/redis/go-redis/v9 v9.14.0 h1:u4tNCjXOyzfgeLN+vAZaW1xUooqWDqVEsZN0U01jfAE=
|
||||
github.com/redis/go-redis/v9 v9.14.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
||||
github.com/redis/rueidis v1.0.64 h1:XqgbueDuNV3qFdVdQwAHJl1uNt90zUuAJuzqjH4cw6Y=
|
||||
github.com/redis/rueidis v1.0.64/go.mod h1:Lkhr2QTgcoYBhxARU7kJRO8SyVlgUuEkcJO1Y8MCluA=
|
||||
github.com/redis/rueidis v1.0.68 h1:gept0E45JGxVigWb3zoWHvxEc4IOC7kc4V/4XvN8eG8=
|
||||
github.com/redis/rueidis v1.0.68/go.mod h1:Lkhr2QTgcoYBhxARU7kJRO8SyVlgUuEkcJO1Y8MCluA=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
|
||||
@@ -708,6 +708,8 @@ github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
|
||||
github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 h1:R/ZjJpjQKsZ6L/+Gf9WHbt31GG8NMVcpRqUE+1mMIyo=
|
||||
github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731/go.mod h1:M9R1FoZ3y//hwwnJtO51ypFGwm8ZfpxPT/ZLtO1mcgQ=
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
@@ -1330,6 +1332,7 @@ github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgc
|
||||
github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs=
|
||||
github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA=
|
||||
github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
||||
github.com/planetscale/vtprotobuf v0.6.0/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc=
|
||||
@@ -1397,6 +1400,7 @@ github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtm
|
||||
github.com/schollz/progressbar/v3 v3.14.6 h1:GyjwcWBAf+GFDMLziwerKvpuS7ZF+mNTAXIB2aspiZs=
|
||||
github.com/schollz/progressbar/v3 v3.14.6/go.mod h1:Nrzpuw3Nl0srLY0VlTvC4V6RL50pcEymjy6qyJAaLa0=
|
||||
github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
|
||||
github.com/segmentio/asm v1.1.4/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg=
|
||||
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
|
||||
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
|
||||
github.com/segmentio/parquet-go v0.0.0-20220811205829-7efc157d28af/go.mod h1:PxYdAI6cGd+s1j4hZDQbz3VFgobF5fDA0weLeNWKTE4=
|
||||
@@ -1935,6 +1939,7 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
|
||||
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
@@ -2001,6 +2006,7 @@ golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
|
||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
@@ -2077,6 +2083,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4/go.mod h1:NnuHhy+bxcg30o7FnVAZbXsPHUDQ9qKWAQKCD7VxFtk=
|
||||
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822 h1:zWFRixYR5QlotL+Uv3YfsPRENIrQFXiGs+iwqel6fOQ=
|
||||
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s=
|
||||
@@ -2107,6 +2114,7 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20251014184007-4626949a642f/go.
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||
google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
|
||||
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
||||
google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
|
||||
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
|
||||
|
||||
@@ -111,17 +111,15 @@ func TestGetHomeDashboard(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func newTestLive(t *testing.T, store db.DB) *live.GrafanaLive {
|
||||
func newTestLive(t *testing.T) *live.GrafanaLive {
|
||||
features := featuremgmt.WithFeatures()
|
||||
cfg := setting.NewCfg()
|
||||
cfg.AppURL = "http://localhost:3000/"
|
||||
gLive, err := live.ProvideService(nil, cfg,
|
||||
routing.NewRouteRegister(),
|
||||
nil, nil, nil, nil,
|
||||
store,
|
||||
nil,
|
||||
&usagestats.UsageStatsMock{T: t},
|
||||
nil,
|
||||
features, acimpl.ProvideAccessControl(features),
|
||||
&dashboards.FakeDashboardService{},
|
||||
nil, nil)
|
||||
@@ -751,7 +749,7 @@ func TestIntegrationDashboardAPIEndpoint(t *testing.T) {
|
||||
hs := HTTPServer{
|
||||
Cfg: cfg,
|
||||
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
|
||||
Live: newTestLive(t, db.InitTestDB(t)),
|
||||
Live: newTestLive(t),
|
||||
QuotaService: quotatest.New(false, nil),
|
||||
LibraryElementService: &libraryelementsfake.LibraryElementService{},
|
||||
DashboardService: dashboardService,
|
||||
@@ -1003,7 +1001,7 @@ func postDashboardScenario(t *testing.T, desc string, url string, routePattern s
|
||||
hs := HTTPServer{
|
||||
Cfg: cfg,
|
||||
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
|
||||
Live: newTestLive(t, db.InitTestDB(t)),
|
||||
Live: newTestLive(t),
|
||||
QuotaService: quotatest.New(false, nil),
|
||||
pluginStore: &pluginstore.FakePluginStore{},
|
||||
LibraryElementService: &libraryelementsfake.LibraryElementService{},
|
||||
@@ -1043,7 +1041,7 @@ func restoreDashboardVersionScenario(t *testing.T, desc string, url string, rout
|
||||
hs := HTTPServer{
|
||||
Cfg: cfg,
|
||||
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
|
||||
Live: newTestLive(t, db.InitTestDB(t)),
|
||||
Live: newTestLive(t),
|
||||
QuotaService: quotatest.New(false, nil),
|
||||
LibraryElementService: &libraryelementsfake.LibraryElementService{},
|
||||
DashboardService: mock,
|
||||
|
||||
@@ -343,7 +343,7 @@ func TestUpdateDataSourceByID_DataSourceNameExists(t *testing.T) {
|
||||
Cfg: setting.NewCfg(),
|
||||
AccessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures()),
|
||||
accesscontrolService: actest.FakeService{},
|
||||
Live: newTestLive(t, nil),
|
||||
Live: newTestLive(t),
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, "/api/datasources/1")
|
||||
@@ -450,7 +450,7 @@ func TestAPI_datasources_AccessControl(t *testing.T) {
|
||||
hs.Cfg = setting.NewCfg()
|
||||
hs.DataSourcesService = &dataSourcesServiceMock{expectedDatasource: &datasources.DataSource{}}
|
||||
hs.accesscontrolService = actest.FakeService{}
|
||||
hs.Live = newTestLive(t, hs.SQLStore)
|
||||
hs.Live = newTestLive(t)
|
||||
hs.promRegister, hs.dsConfigHandlerRequestsDuration = setupDsConfigHandlerMetrics()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package dtos
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type LivePublishCmd struct {
|
||||
Channel string `json:"channel"`
|
||||
Data json.RawMessage `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type LivePublishResponse struct {
|
||||
}
|
||||
Generated
+8
-8
@@ -672,10 +672,7 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
|
||||
starService := starimpl.ProvideService(sqlStore)
|
||||
searchSearchService := search2.ProvideService(cfg, sqlStore, starService, dashboardService, folderimplService, featureToggles, sortService)
|
||||
plugincontextProvider := plugincontext.ProvideService(cfg, cacheService, pluginstoreService, cacheServiceImpl, service15, service13, requestConfigProvider)
|
||||
qsDatasourceClientBuilder := dsquerierclient.NewNullQSDatasourceClientBuilder()
|
||||
exprService := expr.ProvideService(cfg, middlewareHandler, plugincontextProvider, featureToggles, registerer, tracingService, qsDatasourceClientBuilder)
|
||||
queryServiceImpl := query.ProvideService(cfg, cacheServiceImpl, exprService, ossDataSourceRequestValidator, middlewareHandler, plugincontextProvider, qsDatasourceClientBuilder)
|
||||
grafanaLive, err := live.ProvideService(plugincontextProvider, cfg, routeRegisterImpl, pluginstoreService, middlewareHandler, cacheService, cacheServiceImpl, sqlStore, secretsService, usageStats, queryServiceImpl, featureToggles, accessControl, dashboardService, orgService, eventualRestConfigProvider)
|
||||
grafanaLive, err := live.ProvideService(plugincontextProvider, cfg, routeRegisterImpl, pluginstoreService, middlewareHandler, cacheService, cacheServiceImpl, secretsService, usageStats, featureToggles, accessControl, dashboardService, orgService, eventualRestConfigProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -684,6 +681,8 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
|
||||
authnAuthenticator := authnimpl.ProvideAuthnServiceAuthenticateOnly(authnimplService)
|
||||
contexthandlerContextHandler := contexthandler.ProvideService(cfg, authnAuthenticator, featureToggles)
|
||||
logger := loggermw.Provide(cfg, featureToggles)
|
||||
qsDatasourceClientBuilder := dsquerierclient.NewNullQSDatasourceClientBuilder()
|
||||
exprService := expr.ProvideService(cfg, middlewareHandler, plugincontextProvider, featureToggles, registerer, tracingService, qsDatasourceClientBuilder)
|
||||
ngAlert := metrics2.ProvideService()
|
||||
repositoryImpl := annotationsimpl.ProvideService(sqlStore, cfg, featureToggles, tagimplService, tracingService, dBstore, dashboardService, registerer)
|
||||
alertNG, err := ngalert.ProvideService(cfg, featureToggles, cacheServiceImpl, service15, routeRegisterImpl, sqlStore, kvStore, exprService, dataSourceProxyService, quotaService, secretsService, notificationService, ngAlert, folderimplService, accessControl, dashboardService, renderingService, inProcBus, acimplService, repositoryImpl, pluginstoreService, tracingService, dBstore, httpclientProvider, plugincontextProvider, receiverPermissionsService, userService)
|
||||
@@ -708,6 +707,7 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
|
||||
}
|
||||
ossSearchUserFilter := filters.ProvideOSSSearchUserFilter()
|
||||
ossService := searchusers.ProvideUsersService(cfg, ossSearchUserFilter, userService)
|
||||
queryServiceImpl := query.ProvideService(cfg, cacheServiceImpl, exprService, ossDataSourceRequestValidator, middlewareHandler, plugincontextProvider, qsDatasourceClientBuilder)
|
||||
serviceAccountsProxy, err := proxy.ProvideServiceAccountsProxy(cfg, accessControl, acimplService, featureToggles, serviceAccountPermissionsService, serviceAccountsService, routeRegisterImpl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1329,10 +1329,7 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
|
||||
starService := starimpl.ProvideService(sqlStore)
|
||||
searchSearchService := search2.ProvideService(cfg, sqlStore, starService, dashboardService, folderimplService, featureToggles, sortService)
|
||||
plugincontextProvider := plugincontext.ProvideService(cfg, cacheService, pluginstoreService, cacheServiceImpl, service15, service13, requestConfigProvider)
|
||||
qsDatasourceClientBuilder := dsquerierclient.NewNullQSDatasourceClientBuilder()
|
||||
exprService := expr.ProvideService(cfg, middlewareHandler, plugincontextProvider, featureToggles, registerer, tracingService, qsDatasourceClientBuilder)
|
||||
queryServiceImpl := query.ProvideService(cfg, cacheServiceImpl, exprService, ossDataSourceRequestValidator, middlewareHandler, plugincontextProvider, qsDatasourceClientBuilder)
|
||||
grafanaLive, err := live.ProvideService(plugincontextProvider, cfg, routeRegisterImpl, pluginstoreService, middlewareHandler, cacheService, cacheServiceImpl, sqlStore, secretsService, usageStats, queryServiceImpl, featureToggles, accessControl, dashboardService, orgService, eventualRestConfigProvider)
|
||||
grafanaLive, err := live.ProvideService(plugincontextProvider, cfg, routeRegisterImpl, pluginstoreService, middlewareHandler, cacheService, cacheServiceImpl, secretsService, usageStats, featureToggles, accessControl, dashboardService, orgService, eventualRestConfigProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1341,6 +1338,8 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
|
||||
authnAuthenticator := authnimpl.ProvideAuthnServiceAuthenticateOnly(authnimplService)
|
||||
contexthandlerContextHandler := contexthandler.ProvideService(cfg, authnAuthenticator, featureToggles)
|
||||
logger := loggermw.Provide(cfg, featureToggles)
|
||||
qsDatasourceClientBuilder := dsquerierclient.NewNullQSDatasourceClientBuilder()
|
||||
exprService := expr.ProvideService(cfg, middlewareHandler, plugincontextProvider, featureToggles, registerer, tracingService, qsDatasourceClientBuilder)
|
||||
notificationServiceMock := notifications.MockNotificationService()
|
||||
ngAlert := metrics2.ProvideServiceForTest()
|
||||
repositoryImpl := annotationsimpl.ProvideService(sqlStore, cfg, featureToggles, tagimplService, tracingService, dBstore, dashboardService, registerer)
|
||||
@@ -1366,6 +1365,7 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
|
||||
}
|
||||
ossSearchUserFilter := filters.ProvideOSSSearchUserFilter()
|
||||
ossService := searchusers.ProvideUsersService(cfg, ossSearchUserFilter, userService)
|
||||
queryServiceImpl := query.ProvideService(cfg, cacheServiceImpl, exprService, ossDataSourceRequestValidator, middlewareHandler, plugincontextProvider, qsDatasourceClientBuilder)
|
||||
serviceAccountsProxy, err := proxy.ProvideServiceAccountsProxy(cfg, accessControl, acimplService, featureToggles, serviceAccountPermissionsService, serviceAccountsService, routeRegisterImpl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
)
|
||||
|
||||
type Storage struct {
|
||||
store db.DB
|
||||
cache *localcache.CacheService
|
||||
}
|
||||
|
||||
func NewStorage(store db.DB, cache *localcache.CacheService) *Storage {
|
||||
return &Storage{store: store, cache: cache}
|
||||
}
|
||||
|
||||
func getLiveMessageCacheKey(orgID int64, channel string) string {
|
||||
return fmt.Sprintf("live_message_%d_%s", orgID, channel)
|
||||
}
|
||||
|
||||
func (s *Storage) SaveLiveMessage(query *model.SaveLiveMessageQuery) error {
|
||||
// Come back to saving into database after evaluating database structure.
|
||||
s.cache.Set(getLiveMessageCacheKey(query.OrgID, query.Channel), model.LiveMessage{
|
||||
ID: 0, // Not used actually.
|
||||
OrgID: query.OrgID,
|
||||
Channel: query.Channel,
|
||||
Data: query.Data,
|
||||
Published: time.Now(),
|
||||
}, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Storage) GetLiveMessage(query *model.GetLiveMessageQuery) (model.LiveMessage, bool, error) {
|
||||
// Come back to saving into database after evaluating database structure.
|
||||
m, ok := s.cache.Get(getLiveMessageCacheKey(query.OrgID, query.Channel))
|
||||
if !ok {
|
||||
return model.LiveMessage{}, false, nil
|
||||
}
|
||||
msg, ok := m.(model.LiveMessage)
|
||||
if !ok {
|
||||
return model.LiveMessage{}, false, fmt.Errorf("unexpected live message type in cache: %T", m)
|
||||
}
|
||||
return msg, true, nil
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/services/live/database"
|
||||
)
|
||||
|
||||
// SetupTestStorage initializes a storage to used by the integration tests.
|
||||
// This is required to properly register and execute migrations.
|
||||
func SetupTestStorage(t *testing.T) *database.Storage {
|
||||
sqlStore := db.InitTestDB(t)
|
||||
localCache := localcache.New(time.Hour, time.Hour)
|
||||
return database.NewStorage(sqlStore, localCache)
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
"github.com/grafana/grafana/pkg/tests/testsuite"
|
||||
"github.com/grafana/grafana/pkg/util/testutil"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testsuite.Run(m)
|
||||
}
|
||||
|
||||
func TestIntegrationLiveMessage(t *testing.T) {
|
||||
testutil.SkipIntegrationTestInShortMode(t)
|
||||
|
||||
storage := SetupTestStorage(t)
|
||||
|
||||
getQuery := &model.GetLiveMessageQuery{
|
||||
OrgID: 1,
|
||||
Channel: "test_channel",
|
||||
}
|
||||
_, ok, err := storage.GetLiveMessage(getQuery)
|
||||
require.NoError(t, err)
|
||||
require.False(t, ok)
|
||||
|
||||
saveQuery := &model.SaveLiveMessageQuery{
|
||||
OrgID: 1,
|
||||
Channel: "test_channel",
|
||||
Data: []byte(`{}`),
|
||||
}
|
||||
err = storage.SaveLiveMessage(saveQuery)
|
||||
require.NoError(t, err)
|
||||
|
||||
msg, ok, err := storage.GetLiveMessage(getQuery)
|
||||
require.NoError(t, err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, int64(1), msg.OrgID)
|
||||
require.Equal(t, "test_channel", msg.Channel)
|
||||
require.Equal(t, json.RawMessage(`{}`), msg.Data)
|
||||
require.NotZero(t, msg.Published)
|
||||
|
||||
// try saving again, should be replaced.
|
||||
saveQuery2 := &model.SaveLiveMessageQuery{
|
||||
OrgID: 1,
|
||||
Channel: "test_channel",
|
||||
Data: []byte(`{"input": "hello"}`),
|
||||
}
|
||||
err = storage.SaveLiveMessage(saveQuery2)
|
||||
require.NoError(t, err)
|
||||
|
||||
getQuery2 := &model.GetLiveMessageQuery{
|
||||
OrgID: 1,
|
||||
Channel: "test_channel",
|
||||
}
|
||||
msg2, ok, err := storage.GetLiveMessage(getQuery2)
|
||||
require.NoError(t, err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, int64(1), msg2.OrgID)
|
||||
require.Equal(t, "test_channel", msg2.Channel)
|
||||
require.Equal(t, json.RawMessage(`{"input": "hello"}`), msg2.Data)
|
||||
require.NotZero(t, msg2.Published)
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package features
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
)
|
||||
|
||||
var (
|
||||
logger = log.New("live.features") // scoped to all features?
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination=broadcast_mock.go -package=features github.com/grafana/grafana/pkg/services/live/features LiveMessageStore
|
||||
|
||||
type LiveMessageStore interface {
|
||||
SaveLiveMessage(query *model.SaveLiveMessageQuery) error
|
||||
GetLiveMessage(query *model.GetLiveMessageQuery) (model.LiveMessage, bool, error)
|
||||
}
|
||||
|
||||
// BroadcastRunner will simply broadcast all events to `grafana/broadcast/*` channels
|
||||
// This assumes that data is a JSON object
|
||||
type BroadcastRunner struct {
|
||||
liveMessageStore LiveMessageStore
|
||||
}
|
||||
|
||||
func NewBroadcastRunner(liveMessageStore LiveMessageStore) *BroadcastRunner {
|
||||
return &BroadcastRunner{liveMessageStore: liveMessageStore}
|
||||
}
|
||||
|
||||
// GetHandlerForPath called on init
|
||||
func (b *BroadcastRunner) GetHandlerForPath(_ string) (model.ChannelHandler, error) {
|
||||
return b, nil // all dashboards share the same handler
|
||||
}
|
||||
|
||||
// OnSubscribe will let anyone connect to the path
|
||||
func (b *BroadcastRunner) OnSubscribe(_ context.Context, u identity.Requester, e model.SubscribeEvent) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
|
||||
reply := model.SubscribeReply{
|
||||
Presence: true,
|
||||
JoinLeave: true,
|
||||
}
|
||||
query := &model.GetLiveMessageQuery{
|
||||
OrgID: u.GetOrgID(),
|
||||
Channel: e.Channel,
|
||||
}
|
||||
msg, ok, err := b.liveMessageStore.GetLiveMessage(query)
|
||||
if err != nil {
|
||||
return model.SubscribeReply{}, 0, err
|
||||
}
|
||||
if ok {
|
||||
reply.Data = msg.Data
|
||||
}
|
||||
return reply, backend.SubscribeStreamStatusOK, nil
|
||||
}
|
||||
|
||||
// OnPublish is called when a client wants to broadcast on the websocket
|
||||
func (b *BroadcastRunner) OnPublish(_ context.Context, u identity.Requester, e model.PublishEvent) (model.PublishReply, backend.PublishStreamStatus, error) {
|
||||
query := &model.SaveLiveMessageQuery{
|
||||
OrgID: u.GetOrgID(),
|
||||
Channel: e.Channel,
|
||||
Data: e.Data,
|
||||
}
|
||||
if err := b.liveMessageStore.SaveLiveMessage(query); err != nil {
|
||||
return model.PublishReply{}, 0, err
|
||||
}
|
||||
return model.PublishReply{Data: e.Data}, backend.PublishStreamStatusOK, nil
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/grafana/grafana/pkg/services/live/features (interfaces: LiveMessageStore)
|
||||
|
||||
// Package features is a generated GoMock package.
|
||||
package features
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
|
||||
model "github.com/grafana/grafana/pkg/services/live/model"
|
||||
)
|
||||
|
||||
// MockLiveMessageStore is a mock of LiveMessageStore interface.
|
||||
type MockLiveMessageStore struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockLiveMessageStoreMockRecorder
|
||||
}
|
||||
|
||||
// MockLiveMessageStoreMockRecorder is the mock recorder for MockLiveMessageStore.
|
||||
type MockLiveMessageStoreMockRecorder struct {
|
||||
mock *MockLiveMessageStore
|
||||
}
|
||||
|
||||
// NewMockLiveMessageStore creates a new mock instance.
|
||||
func NewMockLiveMessageStore(ctrl *gomock.Controller) *MockLiveMessageStore {
|
||||
mock := &MockLiveMessageStore{ctrl: ctrl}
|
||||
mock.recorder = &MockLiveMessageStoreMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockLiveMessageStore) EXPECT() *MockLiveMessageStoreMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// GetLiveMessage mocks base method.
|
||||
func (m *MockLiveMessageStore) GetLiveMessage(arg0 *model.GetLiveMessageQuery) (model.LiveMessage, bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetLiveMessage", arg0)
|
||||
ret0, _ := ret[0].(model.LiveMessage)
|
||||
ret1, _ := ret[1].(bool)
|
||||
ret2, _ := ret[2].(error)
|
||||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// GetLiveMessage indicates an expected call of GetLiveMessage.
|
||||
func (mr *MockLiveMessageStoreMockRecorder) GetLiveMessage(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLiveMessage", reflect.TypeOf((*MockLiveMessageStore)(nil).GetLiveMessage), arg0)
|
||||
}
|
||||
|
||||
// SaveLiveMessage mocks base method.
|
||||
func (m *MockLiveMessageStore) SaveLiveMessage(arg0 *model.SaveLiveMessageQuery) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SaveLiveMessage", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SaveLiveMessage indicates an expected call of SaveLiveMessage.
|
||||
func (mr *MockLiveMessageStoreMockRecorder) SaveLiveMessage(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveLiveMessage", reflect.TypeOf((*MockLiveMessageStore)(nil).SaveLiveMessage), arg0)
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package features
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
func TestNewBroadcastRunner(t *testing.T) {
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
d := NewMockLiveMessageStore(mockCtrl)
|
||||
br := NewBroadcastRunner(d)
|
||||
require.NotNil(t, br)
|
||||
}
|
||||
|
||||
func TestBroadcastRunner_OnSubscribe(t *testing.T) {
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
mockDispatcher := NewMockLiveMessageStore(mockCtrl)
|
||||
|
||||
channel := "stream/channel/test"
|
||||
data := json.RawMessage(`{}`)
|
||||
|
||||
mockDispatcher.EXPECT().GetLiveMessage(&model.GetLiveMessageQuery{
|
||||
OrgID: 1,
|
||||
Channel: channel,
|
||||
}).DoAndReturn(func(query *model.GetLiveMessageQuery) (model.LiveMessage, bool, error) {
|
||||
return model.LiveMessage{
|
||||
Data: data,
|
||||
}, true, nil
|
||||
}).Times(1)
|
||||
|
||||
br := NewBroadcastRunner(mockDispatcher)
|
||||
require.NotNil(t, br)
|
||||
handler, err := br.GetHandlerForPath("test")
|
||||
require.NoError(t, err)
|
||||
reply, status, err := handler.OnSubscribe(
|
||||
context.Background(),
|
||||
&user.SignedInUser{OrgID: 1, UserID: 2},
|
||||
model.SubscribeEvent{Channel: channel, Path: "test"},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, backend.SubscribeStreamStatusOK, status)
|
||||
require.Equal(t, data, reply.Data)
|
||||
require.True(t, reply.Presence)
|
||||
require.True(t, reply.JoinLeave)
|
||||
require.False(t, reply.Recover)
|
||||
}
|
||||
|
||||
func TestBroadcastRunner_OnPublish(t *testing.T) {
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
mockDispatcher := NewMockLiveMessageStore(mockCtrl)
|
||||
|
||||
channel := "stream/channel/test"
|
||||
data := json.RawMessage(`{}`)
|
||||
var orgID int64 = 1
|
||||
|
||||
mockDispatcher.EXPECT().SaveLiveMessage(&model.SaveLiveMessageQuery{
|
||||
OrgID: orgID,
|
||||
Channel: channel,
|
||||
Data: data,
|
||||
}).DoAndReturn(func(query *model.SaveLiveMessageQuery) error {
|
||||
return nil
|
||||
}).Times(1)
|
||||
|
||||
br := NewBroadcastRunner(mockDispatcher)
|
||||
require.NotNil(t, br)
|
||||
handler, err := br.GetHandlerForPath("test")
|
||||
require.NoError(t, err)
|
||||
reply, status, err := handler.OnPublish(
|
||||
context.Background(),
|
||||
&user.SignedInUser{OrgID: 1, UserID: 2},
|
||||
model.PublishEvent{Channel: channel, Path: "test", Data: data},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, backend.PublishStreamStatusOK, status)
|
||||
require.Equal(t, data, reply.Data)
|
||||
}
|
||||
@@ -7,9 +7,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
@@ -35,7 +34,6 @@ type dashboardEvent struct {
|
||||
type DashboardHandler struct {
|
||||
Publisher model.ChannelPublisher
|
||||
ClientCount model.ChannelClientCount
|
||||
Store db.DB
|
||||
DashboardService dashboards.DashboardService
|
||||
AccessControl accesscontrol.AccessControl
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@ import (
|
||||
"errors"
|
||||
|
||||
"github.com/centrifugal/centrifuge"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
"github.com/grafana/grafana/pkg/services/live/orgchannel"
|
||||
|
||||
+17
-59
@@ -15,7 +15,6 @@ import (
|
||||
|
||||
"github.com/centrifugal/centrifuge"
|
||||
"github.com/gobwas/glob"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
@@ -25,12 +24,9 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/live"
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/usagestats"
|
||||
@@ -43,7 +39,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/live/database"
|
||||
"github.com/grafana/grafana/pkg/services/live/features"
|
||||
"github.com/grafana/grafana/pkg/services/live/livecontext"
|
||||
"github.com/grafana/grafana/pkg/services/live/liveplugin"
|
||||
@@ -57,7 +52,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||
"github.com/grafana/grafana/pkg/services/query"
|
||||
"github.com/grafana/grafana/pkg/services/secrets"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
@@ -80,8 +74,8 @@ type CoreGrafanaScope struct {
|
||||
|
||||
func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, routeRegister routing.RouteRegister,
|
||||
pluginStore pluginstore.Store, pluginClient plugins.Client, cacheService *localcache.CacheService,
|
||||
dataSourceCache datasources.CacheService, sqlStore db.DB, secretsService secrets.Service,
|
||||
usageStatsService usagestats.Service, queryDataService query.Service, toggles featuremgmt.FeatureToggles,
|
||||
dataSourceCache datasources.CacheService, secretsService secrets.Service,
|
||||
usageStatsService usagestats.Service, toggles featuremgmt.FeatureToggles,
|
||||
accessControl accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
|
||||
orgService org.Service, configProvider apiserver.RestConfigProvider) (*GrafanaLive, error) {
|
||||
g := &GrafanaLive{
|
||||
@@ -93,9 +87,7 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
|
||||
pluginClient: pluginClient,
|
||||
CacheService: cacheService,
|
||||
DataSourceCache: dataSourceCache,
|
||||
SQLStore: sqlStore,
|
||||
SecretsService: secretsService,
|
||||
queryDataService: queryDataService,
|
||||
channels: make(map[string]model.ChannelHandler),
|
||||
GrafanaScope: CoreGrafanaScope{
|
||||
Features: make(map[string]model.ChannelHandlerFactory),
|
||||
@@ -186,14 +178,11 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
|
||||
dash := &features.DashboardHandler{
|
||||
Publisher: g.Publish,
|
||||
ClientCount: g.ClientCount,
|
||||
Store: sqlStore,
|
||||
DashboardService: dashboardService,
|
||||
AccessControl: accessControl,
|
||||
}
|
||||
g.storage = database.NewStorage(g.SQLStore, g.CacheService)
|
||||
g.GrafanaScope.Dashboards = dash
|
||||
g.GrafanaScope.Features["dashboard"] = dash
|
||||
g.GrafanaScope.Features["broadcast"] = features.NewBroadcastRunner(g.storage)
|
||||
|
||||
// Testing watch with just the provisioning support -- this will be removed when it is well validated
|
||||
//nolint:staticcheck // not yet migrated to OpenFeature
|
||||
@@ -388,14 +377,14 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
|
||||
UserID: strconv.FormatInt(id, 10),
|
||||
}
|
||||
newCtx := centrifuge.SetCredentials(ctx.Req.Context(), cred)
|
||||
newCtx = livecontext.SetContextSignedUser(newCtx, user)
|
||||
newCtx = identity.WithRequester(newCtx, user)
|
||||
r := ctx.Req.WithContext(newCtx)
|
||||
wsHandler.ServeHTTP(ctx.Resp, r)
|
||||
}
|
||||
|
||||
g.pushWebsocketHandler = func(ctx *contextmodel.ReqContext) {
|
||||
user := ctx.SignedInUser
|
||||
newCtx := livecontext.SetContextSignedUser(ctx.Req.Context(), user)
|
||||
newCtx := identity.WithRequester(ctx.Req.Context(), user)
|
||||
newCtx = livecontext.SetContextStreamID(newCtx, web.Params(ctx.Req)[":streamId"])
|
||||
r := ctx.Req.WithContext(newCtx)
|
||||
pushWSHandler.ServeHTTP(ctx.Resp, r)
|
||||
@@ -403,7 +392,7 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
|
||||
|
||||
g.pushPipelineWebsocketHandler = func(ctx *contextmodel.ReqContext) {
|
||||
user := ctx.SignedInUser
|
||||
newCtx := livecontext.SetContextSignedUser(ctx.Req.Context(), user)
|
||||
newCtx := identity.WithRequester(ctx.Req.Context(), user)
|
||||
newCtx = livecontext.SetContextChannelID(newCtx, web.Params(ctx.Req)["*"])
|
||||
r := ctx.Req.WithContext(newCtx)
|
||||
pushPipelineWSHandler.ServeHTTP(ctx.Resp, r)
|
||||
@@ -475,14 +464,12 @@ type GrafanaLive struct {
|
||||
RouteRegister routing.RouteRegister
|
||||
CacheService *localcache.CacheService
|
||||
DataSourceCache datasources.CacheService
|
||||
SQLStore db.DB
|
||||
SecretsService secrets.Service
|
||||
pluginStore pluginstore.Store
|
||||
pluginClient plugins.Client
|
||||
queryDataService query.Service
|
||||
orgService org.Service
|
||||
|
||||
keyPrefix string
|
||||
keyPrefix string // HA prefix for grafana cloud (since the org is always 1)
|
||||
|
||||
node *centrifuge.Node
|
||||
surveyCaller *survey.Caller
|
||||
@@ -505,7 +492,6 @@ type GrafanaLive struct {
|
||||
|
||||
contextGetter *liveplugin.ContextGetter
|
||||
runStreamManager *runstream.Manager
|
||||
storage *database.Storage
|
||||
|
||||
usageStatsService usagestats.Service
|
||||
usageStats usageStats
|
||||
@@ -673,18 +659,13 @@ func (g *GrafanaLive) HandleDatasourceUpdate(orgID int64, dsUID string) {
|
||||
}
|
||||
}
|
||||
|
||||
// Use a configuration that's compatible with the standard library
|
||||
// to minimize the risk of introducing bugs. This will make sure
|
||||
// that map keys is ordered.
|
||||
var jsonStd = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
func (g *GrafanaLive) handleOnRPC(clientContextWithSpan context.Context, client *centrifuge.Client, e centrifuge.RPCEvent) (centrifuge.RPCReply, error) {
|
||||
logger.Debug("Client calls RPC", "user", client.UserID(), "client", client.ID(), "method", e.Method)
|
||||
if e.Method != "grafana.query" {
|
||||
return centrifuge.RPCReply{}, centrifuge.ErrorMethodNotFound
|
||||
}
|
||||
user, ok := livecontext.GetContextSignedUser(clientContextWithSpan)
|
||||
if !ok {
|
||||
user, err := identity.GetRequester(clientContextWithSpan)
|
||||
if err != nil {
|
||||
logger.Error("No user found in context", "user", client.UserID(), "client", client.ID(), "method", e.Method)
|
||||
return centrifuge.RPCReply{}, centrifuge.ErrorInternal
|
||||
}
|
||||
@@ -694,38 +675,15 @@ func (g *GrafanaLive) handleOnRPC(clientContextWithSpan context.Context, client
|
||||
return centrifuge.RPCReply{}, centrifuge.ErrorExpired
|
||||
}
|
||||
|
||||
var req dtos.MetricRequest
|
||||
err := json.Unmarshal(e.Data, &req)
|
||||
if err != nil {
|
||||
return centrifuge.RPCReply{}, centrifuge.ErrorBadRequest
|
||||
}
|
||||
resp, err := g.queryDataService.QueryData(clientContextWithSpan, user, false, req)
|
||||
if err != nil {
|
||||
logger.Error("Error query data", "user", client.UserID(), "client", client.ID(), "method", e.Method, "error", err)
|
||||
if errors.Is(err, datasources.ErrDataSourceAccessDenied) {
|
||||
return centrifuge.RPCReply{}, ¢rifuge.Error{Code: uint32(http.StatusForbidden), Message: http.StatusText(http.StatusForbidden)}
|
||||
}
|
||||
var gfErr errutil.Error
|
||||
if errors.As(err, &gfErr) && gfErr.Reason.Status() == errutil.StatusBadRequest {
|
||||
return centrifuge.RPCReply{}, ¢rifuge.Error{Code: uint32(http.StatusBadRequest), Message: http.StatusText(http.StatusBadRequest)}
|
||||
}
|
||||
return centrifuge.RPCReply{}, centrifuge.ErrorInternal
|
||||
}
|
||||
data, err := jsonStd.Marshal(resp)
|
||||
if err != nil {
|
||||
logger.Error("Error marshaling query response", "user", client.UserID(), "client", client.ID(), "method", e.Method, "error", err)
|
||||
return centrifuge.RPCReply{}, centrifuge.ErrorInternal
|
||||
}
|
||||
return centrifuge.RPCReply{
|
||||
Data: data,
|
||||
}, nil
|
||||
// RPC events not available
|
||||
return centrifuge.RPCReply{}, centrifuge.ErrorNotAvailable
|
||||
}
|
||||
|
||||
func (g *GrafanaLive) handleOnSubscribe(clientContextWithSpan context.Context, client *centrifuge.Client, e centrifuge.SubscribeEvent) (centrifuge.SubscribeReply, error) {
|
||||
logger.Debug("Client wants to subscribe", "user", client.UserID(), "client", client.ID(), "channel", e.Channel)
|
||||
|
||||
user, ok := livecontext.GetContextSignedUser(clientContextWithSpan)
|
||||
if !ok {
|
||||
user, err := identity.GetRequester(clientContextWithSpan)
|
||||
if err != nil {
|
||||
logger.Error("No user found in context", "user", client.UserID(), "client", client.ID(), "channel", e.Channel)
|
||||
return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal
|
||||
}
|
||||
@@ -830,8 +788,8 @@ func (g *GrafanaLive) handleOnSubscribe(clientContextWithSpan context.Context, c
|
||||
func (g *GrafanaLive) handleOnPublish(clientCtxWithSpan context.Context, client *centrifuge.Client, e centrifuge.PublishEvent) (centrifuge.PublishReply, error) {
|
||||
logger.Debug("Client wants to publish", "user", client.UserID(), "client", client.ID(), "channel", e.Channel)
|
||||
|
||||
user, ok := livecontext.GetContextSignedUser(clientCtxWithSpan)
|
||||
if !ok {
|
||||
user, err := identity.GetRequester(clientCtxWithSpan)
|
||||
if err != nil {
|
||||
logger.Error("No user found in context", "user", client.UserID(), "client", client.ID(), "channel", e.Channel)
|
||||
return centrifuge.PublishReply{}, centrifuge.ErrorInternal
|
||||
}
|
||||
@@ -1083,7 +1041,7 @@ func (g *GrafanaLive) ClientCount(orgID int64, channel string) (int, error) {
|
||||
}
|
||||
|
||||
func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.Response {
|
||||
cmd := dtos.LivePublishCmd{}
|
||||
cmd := model.LivePublishCmd{}
|
||||
if err := web.Bind(ctx.Req, &cmd); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||
}
|
||||
@@ -1122,7 +1080,7 @@ func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.R
|
||||
logger.Error("Error processing input", "user", user, "channel", channel, "error", err)
|
||||
return response.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil)
|
||||
}
|
||||
return response.JSON(http.StatusOK, dtos.LivePublishResponse{})
|
||||
return response.JSON(http.StatusOK, model.LivePublishResponse{})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1150,7 +1108,7 @@ func (g *GrafanaLive) HandleHTTPPublish(ctx *contextmodel.ReqContext) response.R
|
||||
}
|
||||
}
|
||||
logger.Debug("Publication successful", "identity", ctx.GetID(), "channel", cmd.Channel)
|
||||
return response.JSON(http.StatusOK, dtos.LivePublishResponse{})
|
||||
return response.JSON(http.StatusOK, model.LivePublishResponse{})
|
||||
}
|
||||
|
||||
type streamChannelListResponse struct {
|
||||
|
||||
@@ -11,20 +11,17 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/centrifugal/centrifuge"
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
"github.com/go-jose/go-jose/v4/jwt"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/centrifugal/centrifuge"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/usagestats"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/live/livecontext"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tests/testsuite"
|
||||
"github.com/grafana/grafana/pkg/util/testutil"
|
||||
@@ -245,7 +242,7 @@ func Test_handleOnPublish_IDTokenExpiration(t *testing.T) {
|
||||
t.Run("expired token", func(t *testing.T) {
|
||||
expiration := time.Now().Add(-time.Hour)
|
||||
token := createToken(t, &expiration)
|
||||
ctx := livecontext.SetContextSignedUser(context.Background(), &identity.StaticRequester{IDToken: token})
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{IDToken: token})
|
||||
reply, err := g.handleOnPublish(ctx, client, centrifuge.PublishEvent{
|
||||
Channel: "test",
|
||||
Data: []byte("test"),
|
||||
@@ -257,7 +254,7 @@ func Test_handleOnPublish_IDTokenExpiration(t *testing.T) {
|
||||
t.Run("unexpired token", func(t *testing.T) {
|
||||
expiration := time.Now().Add(time.Hour)
|
||||
token := createToken(t, &expiration)
|
||||
ctx := livecontext.SetContextSignedUser(context.Background(), &identity.StaticRequester{IDToken: token})
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{IDToken: token})
|
||||
reply, err := g.handleOnPublish(ctx, client, centrifuge.PublishEvent{
|
||||
Channel: "test",
|
||||
Data: []byte("test"),
|
||||
@@ -280,7 +277,7 @@ func Test_handleOnRPC_IDTokenExpiration(t *testing.T) {
|
||||
t.Run("expired token", func(t *testing.T) {
|
||||
expiration := time.Now().Add(-time.Hour)
|
||||
token := createToken(t, &expiration)
|
||||
ctx := livecontext.SetContextSignedUser(context.Background(), &identity.StaticRequester{IDToken: token})
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{IDToken: token})
|
||||
reply, err := g.handleOnRPC(ctx, client, centrifuge.RPCEvent{
|
||||
Method: "grafana.query",
|
||||
Data: []byte("test"),
|
||||
@@ -292,7 +289,7 @@ func Test_handleOnRPC_IDTokenExpiration(t *testing.T) {
|
||||
t.Run("unexpired token", func(t *testing.T) {
|
||||
expiration := time.Now().Add(time.Hour)
|
||||
token := createToken(t, &expiration)
|
||||
ctx := livecontext.SetContextSignedUser(context.Background(), &identity.StaticRequester{IDToken: token})
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{IDToken: token})
|
||||
reply, err := g.handleOnRPC(ctx, client, centrifuge.RPCEvent{
|
||||
Method: "grafana.query",
|
||||
Data: []byte("test"),
|
||||
@@ -315,7 +312,7 @@ func Test_handleOnSubscribe_IDTokenExpiration(t *testing.T) {
|
||||
t.Run("expired token", func(t *testing.T) {
|
||||
expiration := time.Now().Add(-time.Hour)
|
||||
token := createToken(t, &expiration)
|
||||
ctx := livecontext.SetContextSignedUser(context.Background(), &identity.StaticRequester{IDToken: token})
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{IDToken: token})
|
||||
reply, err := g.handleOnSubscribe(ctx, client, centrifuge.SubscribeEvent{
|
||||
Channel: "test",
|
||||
})
|
||||
@@ -326,7 +323,7 @@ func Test_handleOnSubscribe_IDTokenExpiration(t *testing.T) {
|
||||
t.Run("unexpired token", func(t *testing.T) {
|
||||
expiration := time.Now().Add(time.Hour)
|
||||
token := createToken(t, &expiration)
|
||||
ctx := livecontext.SetContextSignedUser(context.Background(), &identity.StaticRequester{IDToken: token})
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{IDToken: token})
|
||||
reply, err := g.handleOnSubscribe(ctx, client, centrifuge.SubscribeEvent{
|
||||
Channel: "test",
|
||||
})
|
||||
@@ -347,10 +344,8 @@ func setupLiveService(cfg *setting.Cfg, t *testing.T) (*GrafanaLive, error) {
|
||||
cfg,
|
||||
routing.NewRouteRegister(),
|
||||
nil, nil, nil, nil,
|
||||
db.InitTestDB(t),
|
||||
nil,
|
||||
&usagestats.UsageStatsMock{T: t},
|
||||
nil,
|
||||
featuremgmt.WithFeatures(),
|
||||
acimpl.ProvideAccessControl(featuremgmt.WithFeatures()),
|
||||
&dashboards.FakeDashboardService{},
|
||||
@@ -361,7 +356,12 @@ type dummyTransport struct {
|
||||
name string
|
||||
}
|
||||
|
||||
var (
|
||||
_ centrifuge.Transport = (*dummyTransport)(nil)
|
||||
)
|
||||
|
||||
func (t *dummyTransport) Name() string { return t.name }
|
||||
func (t *dummyTransport) AcceptProtocol() string { return "" }
|
||||
func (t *dummyTransport) Protocol() centrifuge.ProtocolType { return centrifuge.ProtocolTypeJSON }
|
||||
func (t *dummyTransport) ProtocolVersion() centrifuge.ProtocolVersion {
|
||||
return centrifuge.ProtocolVersion2
|
||||
|
||||
@@ -2,27 +2,8 @@ package livecontext
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
)
|
||||
|
||||
type signedUserContextKeyType int
|
||||
|
||||
var signedUserContextKey signedUserContextKeyType
|
||||
|
||||
func SetContextSignedUser(ctx context.Context, user identity.Requester) context.Context {
|
||||
ctx = context.WithValue(ctx, signedUserContextKey, user)
|
||||
return ctx
|
||||
}
|
||||
|
||||
func GetContextSignedUser(ctx context.Context) (identity.Requester, bool) {
|
||||
if val := ctx.Value(signedUserContextKey); val != nil {
|
||||
user, ok := val.(identity.Requester)
|
||||
return user, ok
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
type streamIDContextKey struct{}
|
||||
|
||||
func SetContextStreamID(ctx context.Context, streamID string) context.Context {
|
||||
|
||||
@@ -67,21 +67,9 @@ type ChannelHandlerFactory interface {
|
||||
GetHandlerForPath(path string) (ChannelHandler, error)
|
||||
}
|
||||
|
||||
type LiveMessage struct {
|
||||
ID int64 `xorm:"pk autoincr 'id'"`
|
||||
OrgID int64 `xorm:"org_id"`
|
||||
Channel string
|
||||
Data json.RawMessage
|
||||
Published time.Time
|
||||
type LivePublishCmd struct {
|
||||
Channel string `json:"channel"`
|
||||
Data json.RawMessage `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type SaveLiveMessageQuery struct {
|
||||
OrgID int64 `xorm:"org_id"`
|
||||
Channel string
|
||||
Data json.RawMessage
|
||||
}
|
||||
|
||||
type GetLiveMessageQuery struct {
|
||||
OrgID int64 `xorm:"org_id"`
|
||||
Channel string
|
||||
}
|
||||
type LivePublishResponse struct{}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/live/livecontext"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
)
|
||||
|
||||
@@ -25,8 +25,8 @@ func (s *BuiltinDataOutput) Type() string {
|
||||
}
|
||||
|
||||
func (s *BuiltinDataOutput) OutputData(ctx context.Context, vars Vars, data []byte) ([]*ChannelData, error) {
|
||||
u, ok := livecontext.GetContextSignedUser(ctx)
|
||||
if !ok {
|
||||
u, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.New("user not found in context")
|
||||
}
|
||||
handler, _, err := s.channelHandlerGetter.GetChannelHandler(ctx, u, vars.Channel)
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/live"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/services/live/livecontext"
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
)
|
||||
|
||||
@@ -30,8 +29,8 @@ func (s *BuiltinSubscriber) Type() string {
|
||||
}
|
||||
|
||||
func (s *BuiltinSubscriber) Subscribe(ctx context.Context, vars Vars, data []byte) (model.SubscribeReply, backend.SubscribeStreamStatus, error) {
|
||||
u, ok := livecontext.GetContextSignedUser(ctx)
|
||||
if !ok {
|
||||
u, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return model.SubscribeReply{}, backend.SubscribeStreamStatusPermissionDenied, nil
|
||||
}
|
||||
handler, _, err := s.channelHandlerGetter.GetChannelHandler(ctx, u, vars.Channel)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/live/livecontext"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/services/live/managedstream"
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
)
|
||||
@@ -30,8 +30,8 @@ func (s *ManagedStreamSubscriber) Subscribe(ctx context.Context, vars Vars, _ []
|
||||
logger.Error("Error getting managed stream", "error", err)
|
||||
return model.SubscribeReply{}, 0, err
|
||||
}
|
||||
u, ok := livecontext.GetContextSignedUser(ctx)
|
||||
if !ok {
|
||||
u, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return model.SubscribeReply{}, backend.SubscribeStreamStatusPermissionDenied, nil
|
||||
}
|
||||
return stream.OnSubscribe(ctx, u, model.SubscribeEvent{
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/live/model"
|
||||
)
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/services/live/convert"
|
||||
"github.com/grafana/grafana/pkg/services/live/livecontext"
|
||||
"github.com/grafana/grafana/pkg/services/live/pipeline"
|
||||
@@ -44,8 +45,8 @@ func (s *PipelinePushHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
user, ok := livecontext.GetContextSignedUser(r.Context())
|
||||
if !ok {
|
||||
user, err := identity.GetRequester(r.Context())
|
||||
if err != nil {
|
||||
logger.Error("No user found in context")
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
|
||||
@@ -5,8 +5,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
liveDto "github.com/grafana/grafana-plugin-sdk-go/live"
|
||||
|
||||
liveDto "github.com/grafana/grafana-plugin-sdk-go/live"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/services/live/convert"
|
||||
"github.com/grafana/grafana/pkg/services/live/livecontext"
|
||||
"github.com/grafana/grafana/pkg/services/live/managedstream"
|
||||
@@ -47,8 +48,8 @@ func (s *Handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
user, ok := livecontext.GetContextSignedUser(r.Context())
|
||||
if !ok {
|
||||
user, err := identity.GetRequester(r.Context())
|
||||
if err != nil {
|
||||
logger.Error("No user found in context")
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user