lijian 1 年之前
父节点
当前提交
493b06c633

+ 162 - 0
go.mod

@@ -0,0 +1,162 @@
+module sparrow
+
+go 1.21.4
+
+require (
+	github.com/dgrijalva/jwt-go v3.2.0+incompatible
+	github.com/eclipse/paho.mqtt.golang v1.4.3
+	github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab
+	github.com/go-sql-driver/mysql v1.7.1
+	github.com/gogf/gf v1.16.9
+	github.com/gogf/gf/v2 v2.6.1
+	github.com/influxdata/influxdb-client-go/v2 v2.13.0
+	github.com/iris-contrib/middleware/cors v0.0.0-20231105204038-60b21ca77167
+	github.com/iris-contrib/middleware/jwt v0.0.0-20231105204038-60b21ca77167
+	github.com/jinzhu/gorm v1.9.16
+	github.com/kataras/iris v0.0.2
+	github.com/martini-contrib/binding v0.0.0-20160701174519-05d3e151b6cf
+	github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11
+	github.com/opentracing/opentracing-go v1.2.0
+	github.com/prometheus/client_golang v1.18.0
+	github.com/robertkrimen/otto v0.3.0
+	github.com/robfig/cron v1.2.0
+	github.com/satori/go.uuid v1.2.0
+	github.com/segmentio/kafka-go v0.4.47
+	github.com/sirupsen/logrus v1.9.3
+	github.com/streadway/amqp v1.1.0
+	github.com/stretchr/testify v1.8.4
+	github.com/uber/jaeger-client-go v2.30.0+incompatible
+	go.etcd.io/etcd/client/v3 v3.5.11
+	golang.org/x/net v0.19.0
+	golang.org/x/time v0.5.0
+	google.golang.org/grpc v1.60.1
+	google.golang.org/protobuf v1.32.0
+	labix.org/v2/mgo v0.0.0-20140701140051-000000000287
+)
+
+require (
+	github.com/BurntSushi/toml v1.3.2 // indirect
+	github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 // indirect
+	github.com/CloudyKit/jet/v4 v4.1.0 // indirect
+	github.com/CloudyKit/jet/v6 v6.2.0 // indirect
+	github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
+	github.com/Joker/jade v1.1.3 // indirect
+	github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
+	github.com/ajg/form v1.5.1 // indirect
+	github.com/andybalholm/brotli v1.0.6 // indirect
+	github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
+	github.com/aymerick/douceur v0.2.0 // indirect
+	github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible // indirect
+	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/cespare/xxhash/v2 v2.2.0 // indirect
+	github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 // indirect
+	github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
+	github.com/coreos/go-semver v0.3.0 // indirect
+	github.com/coreos/go-systemd/v22 v22.3.2 // indirect
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 // indirect
+	github.com/fatih/color v1.15.0 // indirect
+	github.com/fatih/structs v1.1.0 // indirect
+	github.com/flosch/pongo2/v4 v4.0.2 // indirect
+	github.com/fsnotify/fsnotify v1.7.0 // indirect
+	github.com/go-logr/logr v1.2.4 // indirect
+	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/gobwas/glob v0.2.3 // indirect
+	github.com/gobwas/httphead v0.1.0 // indirect
+	github.com/gobwas/pool v0.2.1 // indirect
+	github.com/gobwas/ws v1.3.0 // indirect
+	github.com/gogo/protobuf v1.3.2 // indirect
+	github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
+	github.com/golang/protobuf v1.5.3 // indirect
+	github.com/golang/snappy v0.0.4 // indirect
+	github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 // indirect
+	github.com/gomodule/redigo v1.8.5 // indirect
+	github.com/google/go-querystring v1.1.0 // indirect
+	github.com/google/uuid v1.4.0 // indirect
+	github.com/gorilla/css v1.0.0 // indirect
+	github.com/gorilla/websocket v1.5.0 // indirect
+	github.com/grokify/html-strip-tags-go v0.0.1 // indirect
+	github.com/hashicorp/go-version v1.2.1 // indirect
+	github.com/imkira/go-interpol v1.1.0 // indirect
+	github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
+	github.com/iris-contrib/go.uuid v2.0.0+incompatible // indirect
+	github.com/iris-contrib/httpexpect/v2 v2.15.2 // indirect
+	github.com/iris-contrib/jade v1.1.4 // indirect
+	github.com/iris-contrib/pongo2 v0.0.1 // indirect
+	github.com/iris-contrib/schema v0.0.6 // indirect
+	github.com/jinzhu/inflection v1.0.0 // indirect
+	github.com/josharian/intern v1.0.0 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/kataras/blocks v0.0.8 // indirect
+	github.com/kataras/golog v0.1.11 // indirect
+	github.com/kataras/iris/v12 v12.2.8 // indirect
+	github.com/kataras/neffos v0.0.22 // indirect
+	github.com/kataras/pio v0.0.13 // indirect
+	github.com/kataras/sitemap v0.0.6 // indirect
+	github.com/kataras/tunnel v0.0.4 // indirect
+	github.com/klauspost/compress v1.17.2 // indirect
+	github.com/mailgun/raymond/v2 v2.0.48 // indirect
+	github.com/mailru/easyjson v0.7.7 // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
+	github.com/mattn/go-runewidth v0.0.15 // indirect
+	github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
+	github.com/mediocregopher/radix/v3 v3.8.1 // indirect
+	github.com/microcosm-cc/bluemonday v1.0.26 // indirect
+	github.com/mitchellh/go-wordwrap v1.0.1 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/nats-io/nats.go v1.28.0 // indirect
+	github.com/nats-io/nkeys v0.4.6 // indirect
+	github.com/nats-io/nuid v1.0.1 // indirect
+	github.com/oapi-codegen/runtime v1.0.0 // indirect
+	github.com/olekukonko/tablewriter v0.0.5 // indirect
+	github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
+	github.com/pierrec/lz4/v4 v4.1.15 // indirect
+	github.com/pkg/errors v0.8.1 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/prometheus/client_model v0.5.0 // indirect
+	github.com/prometheus/common v0.45.0 // indirect
+	github.com/prometheus/procfs v0.12.0 // indirect
+	github.com/rivo/uniseg v0.4.4 // indirect
+	github.com/russross/blackfriday/v2 v2.1.0 // indirect
+	github.com/ryanuber/columnize v2.1.0+incompatible // indirect
+	github.com/sanity-io/litter v1.5.5 // indirect
+	github.com/schollz/closestmatch v2.1.0+incompatible // indirect
+	github.com/sergi/go-diff v1.1.0 // indirect
+	github.com/tdewolff/minify/v2 v2.20.6 // indirect
+	github.com/tdewolff/parse/v2 v2.7.4 // indirect
+	github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
+	github.com/valyala/bytebufferpool v1.0.0 // indirect
+	github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
+	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
+	github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
+	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
+	github.com/xeipuuv/gojsonschema v1.2.0 // indirect
+	github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect
+	github.com/yosssi/ace v0.0.5 // indirect
+	github.com/yudai/gojsondiff v1.0.0 // indirect
+	github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
+	go.etcd.io/etcd/api/v3 v3.5.11 // indirect
+	go.etcd.io/etcd/client/pkg/v3 v3.5.11 // indirect
+	go.opentelemetry.io/otel v1.14.0 // indirect
+	go.opentelemetry.io/otel/sdk v1.14.0 // indirect
+	go.opentelemetry.io/otel/trace v1.14.0 // indirect
+	go.uber.org/atomic v1.7.0 // indirect
+	go.uber.org/multierr v1.6.0 // indirect
+	go.uber.org/zap v1.17.0 // indirect
+	golang.org/x/crypto v0.16.0 // indirect
+	golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
+	golang.org/x/sync v0.4.0 // indirect
+	golang.org/x/sys v0.15.0 // indirect
+	golang.org/x/text v0.14.0 // indirect
+	golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
+	google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect
+	gopkg.in/ini.v1 v1.67.0 // indirect
+	gopkg.in/sourcemap.v1 v1.0.5 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+	launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect
+	moul.io/http2curl/v2 v2.3.0 // indirect
+)

+ 687 - 0
go.sum

@@ -0,0 +1,687 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
+github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c=
+github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
+github.com/CloudyKit/jet/v4 v4.1.0 h1:EvZLdRZYZ6iljADEhrfWSCSNOJRDntNqEJJmeP0Sjg0=
+github.com/CloudyKit/jet/v4 v4.1.0/go.mod h1:DhUsGNEpjPmBD0zmGNP8DaSV1dGO8g9U4adIK8BCWmw=
+github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME=
+github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4=
+github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
+github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
+github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
+github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc=
+github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
+github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk=
+github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
+github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
+github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
+github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0=
+github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM=
+github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
+github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
+github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
+github.com/andybalholm/brotli v1.0.1-0.20200619015827-c3da72aa01ed/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
+github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
+github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
+github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
+github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
+github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
+github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
+github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns=
+github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
+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/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE=
+github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4=
+github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
+github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
+github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
+github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
+github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
+github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM=
+github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
+github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
+github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
+github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
+github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
+github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
+github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
+github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
+github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
+github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
+github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw=
+github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
+github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI=
+github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+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-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk=
+github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
+github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
+github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
+github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
+github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
+github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/ws v1.0.3/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
+github.com/gobwas/ws v1.3.0 h1:sbeU3Y4Qzlb+MOzIe6mQGf7QR4Hkv6ZD0qhGkBFL2O0=
+github.com/gobwas/ws v1.3.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogf/gf v1.16.9 h1:Q803UmmRo59+Ws08sMVFOcd8oNpkSWL9vS33hlo/Cyk=
+github.com/gogf/gf v1.16.9/go.mod h1:8Q/kw05nlVRp+4vv7XASBsMe9L1tsVKiGoeP2AHnlkk=
+github.com/gogf/gf/v2 v2.6.1 h1:n/cfXM506WjhPa6Z1CEDuHNM1XZ7C8JzSDPn2AfuxgQ=
+github.com/gogf/gf/v2 v2.6.1/go.mod h1:x2XONYcI4hRQ/4gMNbWHmZrNzSEIg20s2NULbzom5k0=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
+github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
+github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 h1:EcQR3gusLHN46TAD+G+EbaaqJArt5vHhNpXAa12PQf4=
+github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
+github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
+github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc=
+github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/uuid v1.1.2-0.20200519141726-cb32006e483f/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
+github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
+github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
+github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
+github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
+github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
+github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/influxdata/influxdb-client-go/v2 v2.13.0 h1:ioBbLmR5NMbAjP4UVA5r9b5xGjpABD7j65pI8kFphDM=
+github.com/influxdata/influxdb-client-go/v2 v2.13.0/go.mod h1:k+spCbt9hcvqvUiz0sr5D8LolXHqAAOfPw9v/RIRHl4=
+github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
+github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
+github.com/iris-contrib/go.uuid v2.0.0+incompatible h1:XZubAYg61/JwnJNbZilGjf3b3pB80+OQg2qf6c8BfWE=
+github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
+github.com/iris-contrib/httpexpect/v2 v2.0.5/go.mod h1:JpRu+DEVVCA6KHLKUAs72QoaevQESqLHuG5s1CQ+QiA=
+github.com/iris-contrib/httpexpect/v2 v2.15.2 h1:T9THsdP1woyAqKHwjkEsbCnMefsAFvk8iJJKokcJ3Go=
+github.com/iris-contrib/httpexpect/v2 v2.15.2/go.mod h1:JLDgIqnFy5loDSUv1OA2j0mb6p/rDhiCqigP22Uq9xE=
+github.com/iris-contrib/jade v1.1.4 h1:WoYdfyJFfZIUgqNAeOyRfTNQZOksSlZ6+FnXR3AEpX0=
+github.com/iris-contrib/jade v1.1.4/go.mod h1:EDqR+ur9piDl6DUgs6qRrlfzmlx/D5UybogqrXvJTBE=
+github.com/iris-contrib/middleware/cors v0.0.0-20231105204038-60b21ca77167 h1:zs9HA+Jn+NsbXTH6tER40sFDcnaFUtBljj5YAnwUfk4=
+github.com/iris-contrib/middleware/cors v0.0.0-20231105204038-60b21ca77167/go.mod h1:D/Xr6gLnI2E5jZJ6FC6pLiF1inXUWqnft6DibmTUuBo=
+github.com/iris-contrib/middleware/jwt v0.0.0-20231105204038-60b21ca77167 h1:x2POmaLt4fmAoO8ZvxrqLPRDtB7ZUiR5LC9ftNY8JYc=
+github.com/iris-contrib/middleware/jwt v0.0.0-20231105204038-60b21ca77167/go.mod h1:txkPY4oCyoRH302p0mx6IsAupinDtULtZ84V7L4dN+A=
+github.com/iris-contrib/pongo2 v0.0.1 h1:zGP7pW51oi5eQZMIlGA3I+FHY9/HOQWDB+572yin0to=
+github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
+github.com/iris-contrib/schema v0.0.2/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA=
+github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw=
+github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA=
+github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
+github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
+github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
+github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
+github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
+github.com/kataras/blocks v0.0.2/go.mod h1:KPyOYc1M3MgzsznVcdjErtcYWO3AZXQbQ8fMYWcr3oA=
+github.com/kataras/blocks v0.0.8 h1:MrpVhoFTCR2v1iOOfGng5VJSILKeZZI+7NGfxEh3SUM=
+github.com/kataras/blocks v0.0.8/go.mod h1:9Jm5zx6BB+06NwA+OhTbHW1xkMOYxahnqTN5DveZ2Yg=
+github.com/kataras/golog v0.0.18/go.mod h1:jRYl7dFYqP8aQj9VkwdBUXYZSfUktm+YYg1arJILfyw=
+github.com/kataras/golog v0.1.11 h1:dGkcCVsIpqiAMWTlebn/ZULHxFvfG4K43LF1cNWSh20=
+github.com/kataras/golog v0.1.11/go.mod h1:mAkt1vbPowFUuUGvexyQ5NFW6djEgGyxQBIARJ0AH4A=
+github.com/kataras/iris v0.0.2 h1:Tteb6pXLN9QiXvTCXCP31LRHu1LHlVA6Rappr9vWa1c=
+github.com/kataras/iris v0.0.2/go.mod h1:ab8yy1jWHFgoI+/B+zoIsQpVY/XUY+NNvVCXJ27Zat8=
+github.com/kataras/iris/v12 v12.2.8 h1:p+PcqyO45dSib8B4I8Wc0fz+6B/CVkOsikCpbeNOkuo=
+github.com/kataras/iris/v12 v12.2.8/go.mod h1:on94BX0C5jhuxgWKDZVpcTqymksZDIxWFN+nL7axjRA=
+github.com/kataras/neffos v0.0.16/go.mod h1:BqWkF1c6cSyqw85dfCdqXxK5cMo/hyBGhtNuFkxHyMg=
+github.com/kataras/neffos v0.0.22 h1:3M4lHrUl//2OKmS9t9z3AKIZqwha6ABeA6WoF03HEv8=
+github.com/kataras/neffos v0.0.22/go.mod h1:IIJZcUDvwBxJGlDj942dqQgyznVKYDti91f8Ez+RRxE=
+github.com/kataras/pio v0.0.8/go.mod h1:NFfMp2kVP1rmV4N6gH6qgWpuoDKlrOeYi3VrAIWCGsE=
+github.com/kataras/pio v0.0.13 h1:x0rXVX0fviDTXOOLOmr4MUxOabu1InVSTu5itF8CXCM=
+github.com/kataras/pio v0.0.13/go.mod h1:k3HNuSw+eJ8Pm2lA4lRhg3DiCjVgHlP8hmXApSej3oM=
+github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
+github.com/kataras/sitemap v0.0.6 h1:w71CRMMKYMJh6LR2wTgnk5hSgjVNB9KL60n5e2KHvLY=
+github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4=
+github.com/kataras/tunnel v0.0.1/go.mod h1:Gslr6f+Y0esb704OqMi8hNOfFImgXcmg4KiN2zScgvs=
+github.com/kataras/tunnel v0.0.4 h1:sCAqWuJV7nPzGrlb0os3j49lk2JhILT0rID38NHNLpA=
+github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
+github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
+github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+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/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/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
+github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
+github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
+github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw=
+github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/martini-contrib/binding v0.0.0-20160701174519-05d3e151b6cf h1:6YSkbjZVghliN7zwJC/U3QQG+OVXOrij3qQ8sxfPIMg=
+github.com/martini-contrib/binding v0.0.0-20160701174519-05d3e151b6cf/go.mod h1:aCggxkm1kuifLw/LEQUbz91N1ZM6PhV7dz03xPQduZA=
+github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11 h1:YFh+sjyJTMQSYjKwM4dFKhJPJC/wfo98tPUc17HdoYw=
+github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:Ah2dBMoxZEqk118as2T4u4fjfXarE0pPnMJaArZQZsI=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
+github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
+github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
+github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
+github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
+github.com/mediocregopher/radix/v3 v3.5.0/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
+github.com/mediocregopher/radix/v3 v3.5.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
+github.com/mediocregopher/radix/v3 v3.8.1 h1:rOkHflVuulFKlwsLY01/M2cM2tWCjDoETcMqKbAWu1M=
+github.com/mediocregopher/radix/v3 v3.8.1/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
+github.com/microcosm-cc/bluemonday v1.0.3/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
+github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
+github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
+github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
+github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
+github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI=
+github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
+github.com/nats-io/jwt/v2 v2.5.3 h1:/9SWvzc6hTfamcgXJ3uYRpgj+QuY2aLNqRiqrKcrpEo=
+github.com/nats-io/jwt/v2 v2.5.3/go.mod h1:iysuPemFcc7p4IoYots3IuELSI4EDe9Y0bQMe+I3Bf4=
+github.com/nats-io/nats-server/v2 v2.9.11 h1:4y5SwWvWI59V5mcqtuoqKq6L9NDUydOP3Ekwuwl8cZI=
+github.com/nats-io/nats-server/v2 v2.9.11/go.mod h1:b0oVuxSlkvS3ZjMkncFeACGyZohbO4XhSqW1Lt7iRRY=
+github.com/nats-io/nats.go v1.9.2/go.mod h1:AjGArbfyR50+afOUotNX2Xs5SYHf+CoOa5HH1eEl2HE=
+github.com/nats-io/nats.go v1.28.0 h1:Th4G6zdsz2d0OqXdfzKLClo6bOfoI/b1kInhRtFIy5c=
+github.com/nats-io/nats.go v1.28.0/go.mod h1:XpbWUlOElGwTYbMR7imivs7jJj9GtK7ypv321Wp6pjc=
+github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nkeys v0.1.4/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
+github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY=
+github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts=
+github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
+github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
+github.com/oapi-codegen/runtime v1.0.0 h1:P4rqFX5fMFWqRzY9M/3YF9+aPSPPB06IzP2P7oOxrWo=
+github.com/oapi-codegen/runtime v1.0.0/go.mod h1:LmCUMQuPB4M/nLXilQXhHw+BLZdDb18B34OO356yJ/A=
+github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
+github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
+github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
+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/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
+github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
+github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
+github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
+github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
+github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
+github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
+github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
+github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
+github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/robertkrimen/otto v0.3.0 h1:5RI+8860NSxvXywDY9ddF5HcPw0puRsd8EgbXV0oqRE=
+github.com/robertkrimen/otto v0.3.0/go.mod h1:uW9yN1CYflmUQYvAMS0m+ZiNo3dMzRUDQJX0jWbzgxw=
+github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
+github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s=
+github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
+github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
+github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
+github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
+github.com/segmentio/kafka-go v0.4.47 h1:IqziR4pA3vrZq7YdRxaT3w1/5fvIH5qpCwstUanQQB0=
+github.com/segmentio/kafka-go v0.4.47/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
+github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693/go.mod h1:6hSY48PjDm4UObWmGLyJE9DxYVKTgR9kbCspXXJEhcU=
+github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM=
+github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8=
+github.com/tdewolff/minify/v2 v2.20.6 h1:R4+Iw1ZqJxrqH52WWHtCpukMuhmO/EasY8YlDiSxphw=
+github.com/tdewolff/minify/v2 v2.20.6/go.mod h1:9t0EY9xySGt1vrP8iscmJfywQwDCQyQBYN6ge+9GwP0=
+github.com/tdewolff/parse/v2 v2.7.4 h1:zrUn2CFg9+5llbUZcsycctFlNRyV1D5gFBZRxuGzdzk=
+github.com/tdewolff/parse/v2 v2.7.4/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
+github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52 h1:gAQliwn+zJrkjAHVcBEYW/RFvd2St4yYimisvozAYlA=
+github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
+github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
+github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
+github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
+github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/vmihailenco/msgpack/v4 v4.3.11/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
+github.com/vmihailenco/msgpack/v5 v5.0.0-beta.1/go.mod h1:xlngVLeyQ/Qi05oQxhQ+oTuqa03RjMwMfk/7/TCs+QI=
+github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
+github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
+github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
+github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
+github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
+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/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
+github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
+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/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
+github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
+github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
+github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
+github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
+github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
+github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
+github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
+github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI=
+github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/etcd/api/v3 v3.5.11 h1:B54KwXbWDHyD3XYAwprxNzTe7vlhR69LuBgZnMVvS7E=
+go.etcd.io/etcd/api/v3 v3.5.11/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4=
+go.etcd.io/etcd/client/pkg/v3 v3.5.11 h1:bT2xVspdiCj2910T0V+/KHcVKjkUrCZVtk8J2JF2z1A=
+go.etcd.io/etcd/client/pkg/v3 v3.5.11/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4=
+go.etcd.io/etcd/client/v3 v3.5.11 h1:ajWtgoNSZJ1gmS8k+icvPtqsqEav+iUorF7b0qozgUU=
+go.etcd.io/etcd/client/v3 v3.5.11/go.mod h1:a6xQUEqFJ8vztO1agJh/KQKOMfFI8og52ZconzcDJwE=
+go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
+go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
+go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
+go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY=
+go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM=
+go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs=
+go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
+go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
+go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
+golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
+golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
+golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
+golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
+golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/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-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
+golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
+gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
+gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
+gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0=
+google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk=
+google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU=
+google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
+google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
+google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
+gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
+gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/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.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+labix.org/v2/mgo v0.0.0-20140701140051-000000000287 h1:L0cnkNl4TfAXzvdrqsYEmxOHOCv2p5I3taaReO8BWFs=
+labix.org/v2/mgo v0.0.0-20140701140051-000000000287/go.mod h1:Lg7AYkt1uXJoR9oeSZ3W/8IXLdvOfIITgZnommstyz4=
+launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54=
+launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM=
+moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
+moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs=
+moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

+ 9 - 0
pkg/protocol/emqx_device.go

@@ -0,0 +1,9 @@
+package protocol
+
+type DevConnectStatus struct {
+	DeviceCode string
+	Reason     string
+	Action     string
+	DeviceId   string
+	ClientIp   string
+}

+ 126 - 0
pkg/protocol/topic.go

@@ -0,0 +1,126 @@
+package protocol
+
+import (
+	"errors"
+	"strings"
+)
+
+/*
+物理型topic:
+$thing/up/status/${productID}/${deviceName}	发布	属性上报
+$thing/down/status/${productID}/${deviceName}	订阅	属性下发与属性上报响应
+$thing/up/event/${productID}/${deviceName}	发布	事件上报
+$thing/down/event/${productID}/${deviceName}	订阅	事件上报响应
+$thing/up/command/${productID}/${deviceName}	发布	设备响应行为执行结果
+$thing/down/command/${productID}/${deviceName}	订阅	应用调用设备行为
+系统级topic:
+$ota/report/${productID}/${deviceName}	发布	固件升级消息上行
+$ota/update/${productID}/${deviceName}	订阅	固件升级消息下行
+$broadcast/rxd/${productID}/${deviceName}	订阅	广播消息下行
+$shadow/operation/up/{productID}/${deviceName}	发布	设备影子消息上行
+$shadow/operation/down/{productID}/${deviceName}	订阅	设备影子消息下行
+$rrpc/txd/{productID}/${deviceName}/${MessageId}	发布	RRPC消息上行,MessageId为RRPC消息ID
+$rrpc/rxd/{productID}/${deviceName}/+	订阅	RRPC消息下行
+$sys/operation/up/{productID}/${deviceName}	发布	系统topic:ntp服务消息上行
+$sys/operation/down/{productID}/${deviceName}/+	订阅	系统topic:ntp服务消息下行
+log topic
+$log/up/operation/${productID}/${deviceName} //设备查询是否需要上传调试日志及日志级别,上行
+$log/down/operation/${productID}/${deviceName}
+$log/up/report/${productID}/${deviceName} //设备上传调试日志内容,上行
+$log/down/report/${productID}/${deviceName}
+$log/down/update/${productID}/${deviceName} //服务器端下发调试日志配置,下行
+
+自定义topic:
+${productID}/${deviceName}/control	订阅	编辑删除
+${productID}/${deviceName}/data	订阅和发布	编辑删除
+${productID}/${deviceName}/event	发布
+${productID}/${deviceName}/xxxxx	订阅和发布   //自定义 暂不做支持
+*/
+const (
+	TopicHeadThing   = "$thing"
+	Thing            = "thing"
+	TopicHeadOta     = "$ota"
+	Ota              = "ota"
+	TopicHeadConfig  = "$config"
+	Config           = "config"
+	TopicHeadLog     = "$log"
+	Log              = "log"
+	TopicHeadShadow  = "$shadow"
+	Shadow           = "shadow"
+	TopicHeadGateway = "$gateway"
+	Gateway          = "gateway"
+	TopicHeadExt     = "$ext"
+	Ext              = "ext"
+)
+
+type Direction int
+
+const (
+	Unknown Direction = iota //设备通信流向:未知
+	Up                       //设备通信流向:上行
+	Down                     //设备通信流向:下行
+)
+
+type TopicInfo struct {
+	ProductKey string
+	DeviceCode string
+	Direction  Direction
+	Types      []string
+	TopicHead  string
+}
+
+func GetTopicInfo(topic string) (topicInfo *TopicInfo, err error) {
+	keys := strings.Split(topic, "/")
+	return parseTopic(keys)
+}
+func parseTopic(topics []string) (topicInfo *TopicInfo, err error) {
+	if len(topics) < 2 {
+		return nil, errors.New("topic is err")
+	}
+	switch topics[0] {
+	case TopicHeadThing, TopicHeadOta, TopicHeadShadow, TopicHeadLog, TopicHeadConfig, TopicHeadGateway, TopicHeadExt:
+		return parseLast(topics)
+	default: //自定义消息
+		return parsePose(0, topics)
+	}
+}
+func parsePose(productPos int, topics []string) (topicInfo *TopicInfo, err error) {
+	return nil, errors.New("topic is err")
+	//先不考虑自定义消息
+	//if len(topics) < (productPos + 2) {
+	//	return nil, errors.Parameter.AddDetail("topic is err")
+	//}
+	//return &TopicInfo{
+	//	ProductID:  topics[productPos],
+	//	DeviceName: topics[productPos+1],
+	//	TopicHead:  topics[0],
+	//}, err
+}
+func parseLast(topics []string) (topicInfo *TopicInfo, err error) {
+	if len(topics) < 4 {
+		return nil, errors.New("topic is err")
+	}
+	return &TopicInfo{
+		ProductKey: topics[len(topics)-2],
+		DeviceCode: topics[len(topics)-1],
+		Direction:  getDirection(topics[1]),
+		Types:      topics[2 : len(topics)-2],
+		TopicHead:  topics[0],
+	}, err
+}
+
+func GetCommandTopic(deviceCode, productKey string) string {
+	topic := strings.Join([]string{TopicHeadThing, "down", "command", productKey, deviceCode}, "/")
+	return topic
+}
+
+func getDirection(dir string) Direction {
+	switch dir {
+	case "up":
+		return Up
+	case "down":
+		return Down
+	default:
+		return Unknown
+	}
+}

+ 13 - 0
pkg/rpcs/task.go

@@ -0,0 +1,13 @@
+package rpcs
+
+// ArgsSubmitTask 任务提交参数
+type ArgsSubmitTask struct {
+	Type string // 任务类型,(timer|以后扩展)
+	Data string // 任务配置JSON字符串
+}
+
+type ArgsSubmitTaskLifecycle struct {
+	TaskId string
+	Action string
+	Data   string
+}

+ 130 - 0
pkg/rule/task_lifecycle_consumer.go

@@ -0,0 +1,130 @@
+package rule
+
+import (
+	"encoding/json"
+	"github.com/streadway/amqp"
+	"sparrow/pkg/server"
+)
+
+type ExternalConsumer interface {
+	AddMessageHandle(msg *TaskLifecycleMessage) error
+	RemoveMessageHandle(msg *TaskLifecycleMessage) error
+	UpdateMessageHandle(msg *TaskLifecycleMessage) error
+	SnapMessageHandle(msg *TaskLifecycleMessage) error
+}
+
+const TaskLifecycleExchange = "task_lifecycle_exchange"
+const TaskExchange = "task_exchange"
+
+type TaskLifecycleConsumer struct {
+	ch          *amqp.Channel
+	ec          ExternalConsumer
+	stopChan    chan struct{}
+	messageChan chan []byte
+}
+
+func NewTaskLifecycleConsumer(ch *amqp.Channel) *TaskLifecycleConsumer {
+	return &TaskLifecycleConsumer{
+		ch:          ch,
+		stopChan:    make(chan struct{}),
+		messageChan: make(chan []byte, 10),
+	}
+}
+
+func (a *TaskLifecycleConsumer) SetExternalConsumer(ec ExternalConsumer) {
+	a.ec = ec
+}
+
+func (a *TaskLifecycleConsumer) Stop() {
+	close(a.stopChan)
+}
+
+func (a *TaskLifecycleConsumer) Start() error {
+	go func() {
+		for {
+			select {
+			case <-a.stopChan:
+				return
+			case msg := <-a.messageChan:
+				a.handleMessage(msg)
+			}
+		}
+	}()
+	return nil
+}
+
+func (a *TaskLifecycleConsumer) handleMessage(msg []byte) {
+	if a.ec == nil {
+		server.Log.Errorf("TaskLifecycleConsumer is unset")
+		return
+	}
+	var tm TaskLifecycleMessage
+	err := json.Unmarshal(msg, &tm)
+	if err != nil {
+		server.Log.Errorf("handle lifecycle message error :%v", err)
+		return
+	}
+	switch tm.Action {
+	case "add":
+		err = a.ec.AddMessageHandle(&tm)
+	case "remove":
+		err = a.ec.RemoveMessageHandle(&tm)
+	case "update":
+		err = a.ec.UpdateMessageHandle(&tm)
+	case "snap":
+		err = a.ec.SnapMessageHandle(&tm)
+	}
+}
+
+func (a *TaskLifecycleConsumer) Init() error {
+	err := a.ch.ExchangeDeclare(
+		TaskLifecycleExchange, // name
+		"fanout",              // type
+		true,                  // durable
+		false,                 // auto-deleted
+		false,                 // internal
+		false,                 // no-wait
+		nil,                   // arguments
+	)
+	if err != nil {
+		return err
+	}
+	//绑定queue到交换机
+	q, err := a.ch.QueueDeclare(
+		"",    // name
+		false, // durable
+		false, // delete when unused
+		true,  // exclusive
+		false, // no-wait
+		nil,   // arguments
+	)
+	if err != nil {
+		return err
+	}
+	err = a.ch.QueueBind(
+		q.Name, // queue name
+		"",     // routing key
+		TaskLifecycleExchange,
+		false,
+		nil,
+	)
+	if err != nil {
+		return err
+	}
+	// creat consumer
+	msg, err := a.ch.Consume(q.Name, "", true, false, false, false, nil)
+	if err != nil {
+		return err
+	}
+	go func() {
+		for {
+			select {
+			case <-a.stopChan:
+				return
+			case d := <-msg:
+				a.messageChan <- d.Body
+			}
+		}
+	}()
+	return nil
+}

+ 44 - 0
pkg/rule/task_message.go

@@ -0,0 +1,44 @@
+package rule
+
+type TaskLifecycleMessage struct {
+	TaskId string `json:"task_id"`
+	Action string `json:"action"`
+	Data   string `json:"data"` // 具体的任务操作配置JSON字符串
+}
+
+// TimerTaskMessage 定时任务消息
+type TimerTaskMessage struct {
+	TaskId  string        `json:"task_id"` // 任务Id
+	Cron    string        `json:"cron"`    // 任务执行的cron表达式
+	Actions []*TaskAction `json:"actions"` // 执行动作列表
+}
+
+// TaskAction 定时任务执行动作
+type TaskAction struct {
+	EntityId string `json:"entity_id"` // 被执行实体Id,指向设备编码
+	/*
+		动作对象类型。
+		delay:延时
+		device_issue:设备指令下发
+		device_group_issue:群组指令下发
+	*/
+	ActionExecutor   string                `json:"action_executor"`   // 动作对象类型。
+	SubEntityId      string                `json:"sub_entity_id"`     // 实体子设备Id,如果需要
+	ExecutorProperty *TaskExecutorProperty `json:"executor_property"` // 动作执行明细
+}
+
+// TaskExecutorProperty 定时任务执行动作执行参数
+type TaskExecutorProperty struct {
+	/*
+		指令 code。当 action_executor 是 device_issue 或 device_group_issue 时,此参数必填。
+	*/
+	FunctionCode string `json:"function_code"`
+	/*
+		指令 value。当 action_executor 是 device_issue 或 device_group_issue 时,此参数必填。
+	*/
+	FunctionValue map[string]interface{} `json:"function_value"`
+	/*
+		延时时间。当 action_executor 是 delay 时,此参数必填。
+	*/
+	DelaySeconds int64 `json:"delay_seconds"`
+}

+ 261 - 0
services/emqx-agent/agent.go

@@ -0,0 +1,261 @@
+package main
+
+import (
+	"context"
+	"github.com/gogf/gf/encoding/gjson"
+	"sparrow/pkg/klink"
+	"sparrow/pkg/models"
+	"sparrow/pkg/protocol"
+	"sparrow/pkg/rpcs"
+	"sparrow/pkg/server"
+	"time"
+)
+
+type Access struct {
+	client SubDev
+}
+
+// Message 收到设备上报消息处理
+func (a *Access) Message(topic string, payload []byte) error {
+
+	topicInfo, err := protocol.GetTopicInfo(topic)
+	if err != nil {
+		return err
+	}
+	if topicInfo.Direction == protocol.Down {
+		return nil
+	}
+	device := &models.Device{}
+	err = server.RPCCallByName(nil, rpcs.RegistryServerName, "Registry.FindDeviceByIdentifier", topicInfo.DeviceCode, device)
+	if err != nil {
+		server.Log.Errorf("device not found %s", topicInfo.DeviceCode)
+		return nil
+	}
+	server.Log.Debugf("device {%v} message {%v} : %s", device.DeviceIdentifier, topicInfo.Types, payload)
+	if len(topicInfo.Types) == 0 {
+		return nil
+	}
+	jsonPayload, err := gjson.DecodeToJson(payload)
+	if err != nil {
+		return nil
+	}
+
+	switch topicInfo.Types[0] {
+	case "status":
+		return a.processStatus(topicInfo.DeviceCode, device.VendorID, jsonPayload)
+	case "event":
+		return a.processEvent(topicInfo.DeviceCode, device.VendorID, jsonPayload)
+	}
+	return nil
+}
+
+func (a *Access) processEvent(deviceId, vendorId string, message *gjson.Json) error {
+	reply := rpcs.ReplyOnEvent{}
+	args := rpcs.ArgsOnEvent{
+		DeviceId:    deviceId,
+		TimeStamp:   message.GetUint64("timestamp"),
+		SubDeviceId: message.GetString("subDeviceId"),
+		SubData:     message.GetJson("data").MustToJson(),
+		VendorId:    vendorId,
+	}
+	err := server.RPCCallByName(nil, rpcs.ControllerName, "Controller.OnEvent", args, &reply)
+	if err != nil {
+		server.Log.Errorf("device on event error. args: %v, error: %v", args, err)
+		return err
+	}
+	return nil
+}
+
+func (a *Access) processStatus(deviceId, vendorId string, message *gjson.Json) error {
+	act := klink.PacketAction(message.GetString("action"))
+	if act != "" {
+		switch act {
+		case klink.DevSendAction:
+			processReportStatus(deviceId, vendorId, message)
+		case klink.DevLoginAction:
+			_ = processDevLogin(deviceId, message.GetString("subDeviceId"))
+		case klink.DevLogoutAction:
+			_ = processDevLogout(deviceId, message.GetString("subDeviceId"))
+		case klink.DevNetConfigAction:
+			_ = processDevNetConfig(deviceId, message.GetString("md5"))
+		case klink.ReportFirmwareAction:
+			_ = processDeviceReportUpgrade(deviceId, message.GetString("version"))
+		}
+	}
+	return nil
+}
+func processDevLogin(deviceCode, subDeviceId string) error {
+	var args rpcs.SubDeviceArgs
+	args.DeviceCode = deviceCode
+	args.Status = 1
+	args.SubDeviceId = subDeviceId
+	var reply *models.SubDevice
+	err := server.RPCCallByName(context.Background(), rpcs.RegistryServerName, "Registry.UpdateSubDevice", &args, &reply)
+	if err != nil {
+		server.Log.Errorf("子设备上线出错:%s", err.Error())
+	}
+	return nil
+}
+
+func processDevLogout(deviceCode, subDeviceId string) error {
+	var args rpcs.SubDeviceArgs
+	args.DeviceCode = deviceCode
+	args.Status = 0
+	args.SubDeviceId = subDeviceId
+	var reply *models.SubDevice
+	err := server.RPCCallByName(context.Background(), rpcs.RegistryServerName, "Registry.UpdateSubDevice", &args, &reply)
+	if err != nil {
+		server.Log.Errorf("子设备下线出错:%s", err.Error())
+	}
+	return nil
+}
+
+// 处理设备配网信息
+func processDevNetConfig(deviceCode, md5 string) error {
+	args := &models.DeviceNetConfig{
+		DeviceIdentifier: deviceCode,
+		MD5:              md5,
+		Status:           1,
+	}
+	reply := rpcs.ReplyCheckDeviceNetConfig{}
+	err := server.RPCCallByName(nil, rpcs.RegistryServerName, "Registry.CreateDeviceNetConfig", args, &reply)
+	if err != nil {
+		server.Log.Errorf("set device:%s net config info error:%v", deviceCode, err)
+	}
+	return nil
+}
+
+// 设备上报固件信息处理
+func processDeviceReportUpgrade(deviceId, version string) error {
+	args := &rpcs.ArgsUpdateDeviceVersion{
+		DeviceId: deviceId,
+		Version:  version,
+	}
+	var reply rpcs.ReplyEmptyResult
+	err := server.RPCCallByName(nil, rpcs.RegistryServerName, "Registry.UpdateDeviceVersion", args, &reply)
+	if err != nil {
+		server.Log.Errorf("更新设备版本号失败:%v", err)
+	}
+	return nil
+}
+func processReportStatus(deviceid, vendorId string, message *gjson.Json) {
+	reply := rpcs.ReplyOnStatus{}
+	args := rpcs.ArgsOnStatus{
+		DeviceId:    deviceid,
+		Timestamp:   message.GetUint64("timestamp"),
+		SubData:     message.GetJson("data").MustToJson(),
+		VendorId:    vendorId,
+		SubDeviceId: message.GetString("subDeviceId"),
+		Action:      klink.PacketAction(message.GetString("action")),
+	}
+	err := server.RPCCallByName(nil, rpcs.ControllerName, "Controller.OnStatus", args, &reply)
+	if err != nil {
+		server.Log.Errorf("device report status error. args: %v, error: %v", args, err)
+		return
+	}
+}
+
+// Connected 设备接入时
+func (a *Access) Connected(status *protocol.DevConnectStatus) error {
+	server.Log.Infof("设备上线;%s", status.DeviceId)
+	// 查询设备信息
+	device := &models.Device{}
+	err := server.RPCCallByName(nil, rpcs.RegistryServerName, "Registry.FindDeviceByIdentifier", status.DeviceId, device)
+	if err != nil {
+		server.Log.Errorf("device not found %s", status.DeviceId)
+		return nil
+	}
+	args := rpcs.ArgsGetOnline{
+		Id:                device.DeviceIdentifier,
+		ClientIP:          status.ClientIp,
+		AccessRPCHost:     server.GetRPCHost(),
+		HeartbeatInterval: 300,
+	}
+	reply := rpcs.ReplyGetOnline{}
+	err = server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.GetOnlineV2", args, &reply)
+	if err != nil {
+		server.Log.Errorf("device online error. args: %v, error: %v", args, err)
+	}
+	var cReply rpcs.ReplyEmptyResult
+	var cArgs rpcs.ArgsGetStatus
+	cArgs.VendorId = device.VendorID
+	cArgs.Id = args.Id
+	if err = server.RPCCallByName(nil, rpcs.ControllerName, "Controller.Online", &cArgs, &cReply); err != nil {
+		return err
+	}
+	return nil
+}
+
+// Disconnected 设备断开连接时
+func (a *Access) Disconnected(status *protocol.DevConnectStatus) error {
+	// 查询设备信息
+	device := &models.Device{}
+	err := server.RPCCallByName(nil, rpcs.RegistryServerName, "Registry.FindDeviceByIdentifier", status.DeviceId, device)
+	if err != nil {
+		server.Log.Errorf("device not found %s", status.DeviceId)
+		return nil
+	}
+	args := rpcs.ArgsGetOffline{
+		Id:       device.DeviceIdentifier,
+		VendorId: device.VendorID,
+	}
+	reply := rpcs.ReplyGetOffline{}
+	err = server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.GetOffline", args, &reply)
+	if err != nil {
+		server.Log.Errorf("device offline error. deviceid: %v, error: %v", status.DeviceId, err)
+	}
+	return err
+}
+
+// SendCommand rpc 发送设备命令
+func (a *Access) SendCommand(args rpcs.ArgsSendCommand, reply *rpcs.ReplySendCommand) error {
+	// 查询设备信息
+	device := &models.Device{}
+	err := server.RPCCallByName(nil, rpcs.RegistryServerName, "Registry.FindDeviceByIdentifier", args.DeviceId, device)
+	if err != nil {
+		server.Log.Errorf("device not found %s", args.DeviceId)
+		return nil
+	}
+	product := &models.Product{}
+	err = server.RPCCallByName(nil, rpcs.RegistryServerName, "Registry.FindProduct", device.ProductID, product)
+	if err != nil {
+		server.Log.Errorf("device not found %s", args.DeviceId)
+		return nil
+	}
+	cmd := &klink.CloudSend{
+		Action:      "cloudSend",
+		MsgId:       0,
+		DeviceCode:  args.DeviceId,
+		SubDeviceId: args.SubDevice,
+		Timestamp:   time.Now().Unix(),
+		Data: &klink.CloudSendData{
+			Cmd:    args.Cmd,
+			Params: args.Params,
+		},
+	}
+	msg, err := cmd.Marshal()
+	if err != nil {
+		return err
+	}
+	return a.client.PublishToMsgToDev(protocol.GetCommandTopic(args.DeviceId, product.ProductKey), msg)
+}
+
+// GetStatus rpc 获取设备状态
+func (a *Access) GetStatus(args rpcs.ArgsGetStatus, reply *rpcs.ReplyGetStatus) error {
+	server.Log.Infof("Access Get Status: %v", args)
+	// first send a get status command
+	cmdArgs := rpcs.ArgsSendCommand{
+		DeviceId:  args.Id,
+		WaitTime:  0,
+		SubDevice: args.SubDeviceId,
+		Cmd:       "report",
+	}
+	cmdReply := rpcs.ReplySendCommand{}
+	return a.SendCommand(cmdArgs, &cmdReply)
+}
+
+func NewAgent(client SubDev) *Access {
+	return &Access{
+		client: client,
+	}
+}

+ 9 - 0
services/emqx-agent/client/config.go

@@ -0,0 +1,9 @@
+package client
+
+type MqttConfig struct {
+	ClientId string
+	Brokers  []string
+	User     string
+	Password string
+	ConnNum  int
+}

+ 99 - 0
services/emqx-agent/client/mqtt_client.go

@@ -0,0 +1,99 @@
+package client
+
+import (
+	"crypto/tls"
+	"fmt"
+	MQTT "github.com/eclipse/paho.mqtt.golang"
+	"github.com/gogf/gf/util/guid"
+	"math/rand"
+	"net/url"
+	"sparrow/pkg/server"
+
+	"sync"
+	"time"
+)
+
+var (
+	mqttInitOnce            sync.Once
+	mqttClient              *MqttClient
+	mqttSetOnConnectHandler func(cli MQTT.Client)
+)
+
+type MqttClient struct {
+	clients []MQTT.Client
+}
+
+func NewMqttClient(conf *MqttConfig) (mcs *MqttClient, err error) {
+	mqttInitOnce.Do(func() {
+		var clients []MQTT.Client
+		for len(clients) < conf.ConnNum {
+			var (
+				mc MQTT.Client
+			)
+			for i := 3; i > 0; i-- {
+				mc, err = initMqttClient(conf)
+				if err != nil {
+					server.Log.Errorf("init mqtt client failed: %s", err.Error())
+					continue
+				}
+				break
+			}
+			if err != nil {
+				server.Log.Errorf("mqtt 连接失败: %s", err.Error())
+				panic(err)
+			}
+			clients = append(clients, mc)
+			var cli = MqttClient{clients: clients}
+			mqttClient = &cli
+		}
+	})
+	return mqttClient, err
+}
+
+func initMqttClient(conf *MqttConfig) (mc MQTT.Client, err error) {
+	opts := MQTT.NewClientOptions()
+	for _, broker := range conf.Brokers {
+		opts.AddBroker(broker)
+	}
+	opts.SetClientID(fmt.Sprintf("%s_%s", conf.ClientId, guid.S())).
+		SetUsername(conf.User).SetPassword(conf.Password).
+		SetConnectRetry(true)
+	opts.SetConnectionAttemptHandler(func(broker *url.URL, tlsCfg *tls.Config) *tls.Config {
+		server.Log.Infof("connect to %s", broker.String())
+		return tlsCfg
+	})
+	opts.SetOnConnectHandler(func(client MQTT.Client) {
+		server.Log.Infof("connected success")
+	})
+
+	mc = MQTT.NewClient(opts)
+	if errF := mc.Connect().WaitTimeout(time.Second * 5); errF == false {
+		server.Log.Errorf("connected failed")
+		return
+	}
+	return
+}
+
+// Subscribe 订阅消息
+func (m MqttClient) Subscribe(cli MQTT.Client, topic string, qos byte, callback MQTT.MessageHandler) error {
+	var clients = m.clients
+	if cli != nil {
+		clients = []MQTT.Client{cli}
+	}
+	for _, client := range clients {
+		err := client.Subscribe(topic, qos, callback).Error()
+		if err != nil {
+			server.Log.Errorf("subscribe failed: %s", err.Error())
+		}
+	}
+	return nil
+}
+
+// Publish 发布消息
+func (m MqttClient) Publish(topic string, qos byte, retained bool, payload interface{}) error {
+	id := rand.Intn(len(m.clients))
+	return m.clients[id].Publish(topic, qos, retained, payload).Error()
+}
+func SetMqttSetOnConnectHandler(f func(cli MQTT.Client)) {
+	mqttSetOnConnectHandler = f
+}

+ 6 - 0
services/emqx-agent/config.toml

@@ -0,0 +1,6 @@
+[mqtt]
+client_id = "sparrow"
+brokers = ["114.115.251.196:1883"]
+user = "sparrow_test"
+password = "sparrow_test"
+conn_number = 10

二进制
services/emqx-agent/go_build_sparrow_services_emqx_agent


+ 256 - 0
services/emqx-agent/main.go

@@ -0,0 +1,256 @@
+package main
+
+import (
+	"context"
+	"github.com/gogf/gf/frame/g"
+	"math"
+	"sparrow/pkg/rpcs"
+	"sparrow/pkg/server"
+	"sparrow/services/emqx-agent/client"
+	"sync"
+	"time"
+
+	pb "sparrow/services/emqx-agent/protobuf"
+)
+
+type Counter struct {
+	count    int64
+	start    int64
+	duration int64
+	maxCount int64
+	lock     sync.Mutex
+}
+
+func NewCounter(duration int64, maxCount int64) *Counter {
+	counter := &Counter{}
+	counter.count = 0
+	counter.start = time.Now().UnixNano() / 1e6 // 当前毫秒时间戳
+	if duration == 0 {
+		counter.duration = math.MaxInt64 // duration传0表示没有时间间隔限制,计数器不刷新
+	} else {
+		counter.duration = duration
+	}
+	counter.maxCount = maxCount
+	return counter
+}
+
+// Count 计数器计数
+// n: 计数值
+// refersh: 计数器是否刷新
+// limit: 是否达到计数最大值
+// num: 计数后计数器的值
+func (counter *Counter) Count(n int64) (refresh bool, limit bool, num int64) {
+	now := time.Now().UnixNano() / 1e6
+	counter.lock.Lock()
+	defer counter.lock.Unlock()
+
+	if now-counter.start < counter.duration {
+		counter.count += n
+		num = counter.count
+		limit = num > counter.maxCount
+	} else {
+		// num = counter.count  // 刷新前的最大计数
+		counter.start = now
+		counter.count = 0
+		refresh = true
+	}
+	return
+}
+
+func (counter *Counter) GetCount() (num int64) {
+	counter.lock.Lock()
+	defer counter.lock.Unlock()
+	return counter.count
+}
+
+var cnter *Counter = NewCounter(0, 100)
+
+// emqttServer is used to implement emqx_exhook_v1.s *emqttServer
+type emqttServer struct {
+	pb.UnimplementedHookProviderServer
+}
+
+// HookProviderServer callbacks
+
+func (s *emqttServer) OnProviderLoaded(ctx context.Context, in *pb.ProviderLoadedRequest) (*pb.LoadedResponse, error) {
+	cnter.Count(1)
+	hooks := []*pb.HookSpec{
+		&pb.HookSpec{Name: "client.connect"},
+		&pb.HookSpec{Name: "client.connack"},
+		&pb.HookSpec{Name: "client.connected"},
+		&pb.HookSpec{Name: "client.disconnected"},
+		&pb.HookSpec{Name: "client.authenticate"},
+		&pb.HookSpec{Name: "client.authorize"},
+		&pb.HookSpec{Name: "client.subscribe"},
+		&pb.HookSpec{Name: "client.unsubscribe"},
+		&pb.HookSpec{Name: "session.created"},
+		&pb.HookSpec{Name: "session.subscribed"},
+		&pb.HookSpec{Name: "session.unsubscribed"},
+		&pb.HookSpec{Name: "session.resumed"},
+		&pb.HookSpec{Name: "session.discarded"},
+		&pb.HookSpec{Name: "session.takenover"},
+		&pb.HookSpec{Name: "session.terminated"},
+		&pb.HookSpec{Name: "message.publish"},
+		&pb.HookSpec{Name: "message.delivered"},
+		&pb.HookSpec{Name: "message.acked"},
+		&pb.HookSpec{Name: "message.dropped"},
+	}
+	return &pb.LoadedResponse{Hooks: hooks}, nil
+}
+
+func (s *emqttServer) OnProviderUnloaded(ctx context.Context, in *pb.ProviderUnloadedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnClientConnect(ctx context.Context, in *pb.ClientConnectRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnClientConnack(ctx context.Context, in *pb.ClientConnackRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnClientConnected(ctx context.Context, in *pb.ClientConnectedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnClientDisconnected(ctx context.Context, in *pb.ClientDisconnectedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnClientAuthenticate(ctx context.Context, in *pb.ClientAuthenticateRequest) (*pb.ValuedResponse, error) {
+	cnter.Count(1)
+	reply := &pb.ValuedResponse{}
+	reply.Type = pb.ValuedResponse_STOP_AND_RETURN
+	reply.Value = &pb.ValuedResponse_BoolResult{BoolResult: true}
+	return reply, nil
+}
+
+func (s *emqttServer) OnClientAuthorize(ctx context.Context, in *pb.ClientAuthorizeRequest) (*pb.ValuedResponse, error) {
+	cnter.Count(1)
+	reply := &pb.ValuedResponse{}
+	reply.Type = pb.ValuedResponse_STOP_AND_RETURN
+	reply.Value = &pb.ValuedResponse_BoolResult{BoolResult: true}
+	return reply, nil
+}
+
+func (s *emqttServer) OnClientSubscribe(ctx context.Context, in *pb.ClientSubscribeRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnClientUnsubscribe(ctx context.Context, in *pb.ClientUnsubscribeRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnSessionCreated(ctx context.Context, in *pb.SessionCreatedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+func (s *emqttServer) OnSessionSubscribed(ctx context.Context, in *pb.SessionSubscribedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnSessionUnsubscribed(ctx context.Context, in *pb.SessionUnsubscribedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnSessionResumed(ctx context.Context, in *pb.SessionResumedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnSessionDiscarded(ctx context.Context, in *pb.SessionDiscardedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnSessionTakenover(ctx context.Context, in *pb.SessionTakenoverRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnSessionTerminated(ctx context.Context, in *pb.SessionTerminatedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnMessagePublish(ctx context.Context, in *pb.MessagePublishRequest) (*pb.ValuedResponse, error) {
+	cnter.Count(1)
+	in.Message.Payload = []byte("hardcode payload by exhook-svr-go :)")
+	reply := &pb.ValuedResponse{}
+	reply.Type = pb.ValuedResponse_STOP_AND_RETURN
+	reply.Value = &pb.ValuedResponse_Message{Message: in.Message}
+	return reply, nil
+}
+
+//case2: stop publish the `t/d` messages
+//func (s *emqttServer) OnMessagePublish(ctx context.Context, in *pb.MessagePublishRequest) (*pb.ValuedResponse, error) {
+//	cnter.Count(1)
+//    if in.Message.Topic == "t/d" {
+//        in.Message.Headers["allow_publish"] = "false"
+//        in.Message.Payload = []byte("")
+//    }
+//	reply := &pb.ValuedResponse{}
+//	reply.Type = pb.ValuedResponse_STOP_AND_RETURN
+//	reply.Value = &pb.ValuedResponse_Message{Message: in.Message}
+//	return reply, nil
+//}
+
+func (s *emqttServer) OnMessageDelivered(ctx context.Context, in *pb.MessageDeliveredRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnMessageDropped(ctx context.Context, in *pb.MessageDroppedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func (s *emqttServer) OnMessageAcked(ctx context.Context, in *pb.MessageAckedRequest) (*pb.EmptySuccess, error) {
+	cnter.Count(1)
+	return &pb.EmptySuccess{}, nil
+}
+
+func main() {
+
+	// init emqttServer
+	err := server.Init(rpcs.EmqxAgentServiceName)
+	if err != nil {
+		server.Log.Fatal(err)
+		return
+	}
+
+	sd, err := NewSubDev(&client.MqttConfig{
+		ClientId: g.Cfg().GetString("mqtt.client_id"),
+		User:     g.Cfg().GetString("mqtt.user"),
+		Password: g.Cfg().GetString("mqtt.password"),
+		Brokers:  g.Cfg().GetStrings("mqtt.brokers"),
+		ConnNum:  10,
+	})
+	if err != nil {
+		panic(err)
+	}
+	agent := NewAgent(sd)
+	err = sd.SubDevMsg(func(ctx context.Context) DevSubHandle {
+		return agent
+	})
+	if err != nil {
+		panic(err)
+	}
+	err = server.RegisterRPCHandler(agent)
+
+	// start to run
+	err = server.Run()
+	if err != nil {
+		server.Log.Fatal(err)
+	}
+}

+ 3455 - 0
services/emqx-agent/protobuf/exhook.pb.go

@@ -0,0 +1,3455 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.32.0
+// 	protoc        v4.25.1
+// source: protobuf/exhook.proto
+
+// The exhook proto version should be fixed as `v2` in EMQX v5.x
+// to make sure the exhook proto version is compatible
+
+package exhook
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type ClientAuthorizeRequest_AuthorizeReqType int32
+
+const (
+	ClientAuthorizeRequest_PUBLISH   ClientAuthorizeRequest_AuthorizeReqType = 0
+	ClientAuthorizeRequest_SUBSCRIBE ClientAuthorizeRequest_AuthorizeReqType = 1
+)
+
+// Enum value maps for ClientAuthorizeRequest_AuthorizeReqType.
+var (
+	ClientAuthorizeRequest_AuthorizeReqType_name = map[int32]string{
+		0: "PUBLISH",
+		1: "SUBSCRIBE",
+	}
+	ClientAuthorizeRequest_AuthorizeReqType_value = map[string]int32{
+		"PUBLISH":   0,
+		"SUBSCRIBE": 1,
+	}
+)
+
+func (x ClientAuthorizeRequest_AuthorizeReqType) Enum() *ClientAuthorizeRequest_AuthorizeReqType {
+	p := new(ClientAuthorizeRequest_AuthorizeReqType)
+	*p = x
+	return p
+}
+
+func (x ClientAuthorizeRequest_AuthorizeReqType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ClientAuthorizeRequest_AuthorizeReqType) Descriptor() protoreflect.EnumDescriptor {
+	return file_protobuf_exhook_proto_enumTypes[0].Descriptor()
+}
+
+func (ClientAuthorizeRequest_AuthorizeReqType) Type() protoreflect.EnumType {
+	return &file_protobuf_exhook_proto_enumTypes[0]
+}
+
+func (x ClientAuthorizeRequest_AuthorizeReqType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use ClientAuthorizeRequest_AuthorizeReqType.Descriptor instead.
+func (ClientAuthorizeRequest_AuthorizeReqType) EnumDescriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{7, 0}
+}
+
+// The responded value type
+//  - contiune: Use the responded value and execute the next hook
+//  - ignore: Ignore the responded value
+//  - stop_and_return: Use the responded value and stop the chain executing
+type ValuedResponse_ResponsedType int32
+
+const (
+	ValuedResponse_CONTINUE        ValuedResponse_ResponsedType = 0
+	ValuedResponse_IGNORE          ValuedResponse_ResponsedType = 1
+	ValuedResponse_STOP_AND_RETURN ValuedResponse_ResponsedType = 2
+)
+
+// Enum value maps for ValuedResponse_ResponsedType.
+var (
+	ValuedResponse_ResponsedType_name = map[int32]string{
+		0: "CONTINUE",
+		1: "IGNORE",
+		2: "STOP_AND_RETURN",
+	}
+	ValuedResponse_ResponsedType_value = map[string]int32{
+		"CONTINUE":        0,
+		"IGNORE":          1,
+		"STOP_AND_RETURN": 2,
+	}
+)
+
+func (x ValuedResponse_ResponsedType) Enum() *ValuedResponse_ResponsedType {
+	p := new(ValuedResponse_ResponsedType)
+	*p = x
+	return p
+}
+
+func (x ValuedResponse_ResponsedType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ValuedResponse_ResponsedType) Descriptor() protoreflect.EnumDescriptor {
+	return file_protobuf_exhook_proto_enumTypes[1].Descriptor()
+}
+
+func (ValuedResponse_ResponsedType) Type() protoreflect.EnumType {
+	return &file_protobuf_exhook_proto_enumTypes[1]
+}
+
+func (x ValuedResponse_ResponsedType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use ValuedResponse_ResponsedType.Descriptor instead.
+func (ValuedResponse_ResponsedType) EnumDescriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{22, 0}
+}
+
+type ProviderLoadedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Broker *BrokerInfo  `protobuf:"bytes,1,opt,name=broker,proto3" json:"broker,omitempty"`
+	Meta   *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ProviderLoadedRequest) Reset() {
+	*x = ProviderLoadedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ProviderLoadedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderLoadedRequest) ProtoMessage() {}
+
+func (x *ProviderLoadedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ProviderLoadedRequest.ProtoReflect.Descriptor instead.
+func (*ProviderLoadedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ProviderLoadedRequest) GetBroker() *BrokerInfo {
+	if x != nil {
+		return x.Broker
+	}
+	return nil
+}
+
+func (x *ProviderLoadedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ProviderUnloadedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ProviderUnloadedRequest) Reset() {
+	*x = ProviderUnloadedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ProviderUnloadedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProviderUnloadedRequest) ProtoMessage() {}
+
+func (x *ProviderUnloadedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ProviderUnloadedRequest.ProtoReflect.Descriptor instead.
+func (*ProviderUnloadedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ProviderUnloadedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientConnectRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Conninfo *ConnInfo `protobuf:"bytes,1,opt,name=conninfo,proto3" json:"conninfo,omitempty"`
+	// MQTT CONNECT packet's properties (MQTT v5.0)
+	//
+	// It should be empty on MQTT v3.1.1/v3.1 or others protocol
+	Props []*Property  `protobuf:"bytes,2,rep,name=props,proto3" json:"props,omitempty"`
+	Meta  *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientConnectRequest) Reset() {
+	*x = ClientConnectRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientConnectRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientConnectRequest) ProtoMessage() {}
+
+func (x *ClientConnectRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientConnectRequest.ProtoReflect.Descriptor instead.
+func (*ClientConnectRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ClientConnectRequest) GetConninfo() *ConnInfo {
+	if x != nil {
+		return x.Conninfo
+	}
+	return nil
+}
+
+func (x *ClientConnectRequest) GetProps() []*Property {
+	if x != nil {
+		return x.Props
+	}
+	return nil
+}
+
+func (x *ClientConnectRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientConnackRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Conninfo   *ConnInfo    `protobuf:"bytes,1,opt,name=conninfo,proto3" json:"conninfo,omitempty"`
+	ResultCode string       `protobuf:"bytes,2,opt,name=result_code,json=resultCode,proto3" json:"result_code,omitempty"`
+	Props      []*Property  `protobuf:"bytes,3,rep,name=props,proto3" json:"props,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,4,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientConnackRequest) Reset() {
+	*x = ClientConnackRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientConnackRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientConnackRequest) ProtoMessage() {}
+
+func (x *ClientConnackRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientConnackRequest.ProtoReflect.Descriptor instead.
+func (*ClientConnackRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *ClientConnackRequest) GetConninfo() *ConnInfo {
+	if x != nil {
+		return x.Conninfo
+	}
+	return nil
+}
+
+func (x *ClientConnackRequest) GetResultCode() string {
+	if x != nil {
+		return x.ResultCode
+	}
+	return ""
+}
+
+func (x *ClientConnackRequest) GetProps() []*Property {
+	if x != nil {
+		return x.Props
+	}
+	return nil
+}
+
+func (x *ClientConnackRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientConnectedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientConnectedRequest) Reset() {
+	*x = ClientConnectedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientConnectedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientConnectedRequest) ProtoMessage() {}
+
+func (x *ClientConnectedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientConnectedRequest.ProtoReflect.Descriptor instead.
+func (*ClientConnectedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *ClientConnectedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *ClientConnectedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientDisconnectedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Reason     string       `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientDisconnectedRequest) Reset() {
+	*x = ClientDisconnectedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientDisconnectedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientDisconnectedRequest) ProtoMessage() {}
+
+func (x *ClientDisconnectedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientDisconnectedRequest.ProtoReflect.Descriptor instead.
+func (*ClientDisconnectedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *ClientDisconnectedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *ClientDisconnectedRequest) GetReason() string {
+	if x != nil {
+		return x.Reason
+	}
+	return ""
+}
+
+func (x *ClientDisconnectedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientAuthenticateRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Result     bool         `protobuf:"varint,2,opt,name=result,proto3" json:"result,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientAuthenticateRequest) Reset() {
+	*x = ClientAuthenticateRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientAuthenticateRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientAuthenticateRequest) ProtoMessage() {}
+
+func (x *ClientAuthenticateRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientAuthenticateRequest.ProtoReflect.Descriptor instead.
+func (*ClientAuthenticateRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *ClientAuthenticateRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *ClientAuthenticateRequest) GetResult() bool {
+	if x != nil {
+		return x.Result
+	}
+	return false
+}
+
+func (x *ClientAuthenticateRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientAuthorizeRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo                             `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Type       ClientAuthorizeRequest_AuthorizeReqType `protobuf:"varint,2,opt,name=type,proto3,enum=emqx.exhook.v2.ClientAuthorizeRequest_AuthorizeReqType" json:"type,omitempty"`
+	Topic      string                                  `protobuf:"bytes,3,opt,name=topic,proto3" json:"topic,omitempty"`
+	Result     bool                                    `protobuf:"varint,4,opt,name=result,proto3" json:"result,omitempty"`
+	Meta       *RequestMeta                            `protobuf:"bytes,5,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientAuthorizeRequest) Reset() {
+	*x = ClientAuthorizeRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientAuthorizeRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientAuthorizeRequest) ProtoMessage() {}
+
+func (x *ClientAuthorizeRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[7]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientAuthorizeRequest.ProtoReflect.Descriptor instead.
+func (*ClientAuthorizeRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *ClientAuthorizeRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *ClientAuthorizeRequest) GetType() ClientAuthorizeRequest_AuthorizeReqType {
+	if x != nil {
+		return x.Type
+	}
+	return ClientAuthorizeRequest_PUBLISH
+}
+
+func (x *ClientAuthorizeRequest) GetTopic() string {
+	if x != nil {
+		return x.Topic
+	}
+	return ""
+}
+
+func (x *ClientAuthorizeRequest) GetResult() bool {
+	if x != nil {
+		return x.Result
+	}
+	return false
+}
+
+func (x *ClientAuthorizeRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientSubscribeRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo   *ClientInfo    `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Props        []*Property    `protobuf:"bytes,2,rep,name=props,proto3" json:"props,omitempty"`
+	TopicFilters []*TopicFilter `protobuf:"bytes,3,rep,name=topic_filters,json=topicFilters,proto3" json:"topic_filters,omitempty"`
+	Meta         *RequestMeta   `protobuf:"bytes,4,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientSubscribeRequest) Reset() {
+	*x = ClientSubscribeRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientSubscribeRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientSubscribeRequest) ProtoMessage() {}
+
+func (x *ClientSubscribeRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[8]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientSubscribeRequest.ProtoReflect.Descriptor instead.
+func (*ClientSubscribeRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *ClientSubscribeRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *ClientSubscribeRequest) GetProps() []*Property {
+	if x != nil {
+		return x.Props
+	}
+	return nil
+}
+
+func (x *ClientSubscribeRequest) GetTopicFilters() []*TopicFilter {
+	if x != nil {
+		return x.TopicFilters
+	}
+	return nil
+}
+
+func (x *ClientSubscribeRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type ClientUnsubscribeRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo   *ClientInfo    `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Props        []*Property    `protobuf:"bytes,2,rep,name=props,proto3" json:"props,omitempty"`
+	TopicFilters []*TopicFilter `protobuf:"bytes,3,rep,name=topic_filters,json=topicFilters,proto3" json:"topic_filters,omitempty"`
+	Meta         *RequestMeta   `protobuf:"bytes,4,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *ClientUnsubscribeRequest) Reset() {
+	*x = ClientUnsubscribeRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientUnsubscribeRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientUnsubscribeRequest) ProtoMessage() {}
+
+func (x *ClientUnsubscribeRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[9]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientUnsubscribeRequest.ProtoReflect.Descriptor instead.
+func (*ClientUnsubscribeRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *ClientUnsubscribeRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *ClientUnsubscribeRequest) GetProps() []*Property {
+	if x != nil {
+		return x.Props
+	}
+	return nil
+}
+
+func (x *ClientUnsubscribeRequest) GetTopicFilters() []*TopicFilter {
+	if x != nil {
+		return x.TopicFilters
+	}
+	return nil
+}
+
+func (x *ClientUnsubscribeRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionCreatedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionCreatedRequest) Reset() {
+	*x = SessionCreatedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[10]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionCreatedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionCreatedRequest) ProtoMessage() {}
+
+func (x *SessionCreatedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[10]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionCreatedRequest.ProtoReflect.Descriptor instead.
+func (*SessionCreatedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *SessionCreatedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionCreatedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionSubscribedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Topic      string       `protobuf:"bytes,2,opt,name=topic,proto3" json:"topic,omitempty"`
+	Subopts    *SubOpts     `protobuf:"bytes,3,opt,name=subopts,proto3" json:"subopts,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,4,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionSubscribedRequest) Reset() {
+	*x = SessionSubscribedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[11]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionSubscribedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionSubscribedRequest) ProtoMessage() {}
+
+func (x *SessionSubscribedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[11]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionSubscribedRequest.ProtoReflect.Descriptor instead.
+func (*SessionSubscribedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *SessionSubscribedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionSubscribedRequest) GetTopic() string {
+	if x != nil {
+		return x.Topic
+	}
+	return ""
+}
+
+func (x *SessionSubscribedRequest) GetSubopts() *SubOpts {
+	if x != nil {
+		return x.Subopts
+	}
+	return nil
+}
+
+func (x *SessionSubscribedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionUnsubscribedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Topic      string       `protobuf:"bytes,2,opt,name=topic,proto3" json:"topic,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionUnsubscribedRequest) Reset() {
+	*x = SessionUnsubscribedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[12]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionUnsubscribedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionUnsubscribedRequest) ProtoMessage() {}
+
+func (x *SessionUnsubscribedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[12]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionUnsubscribedRequest.ProtoReflect.Descriptor instead.
+func (*SessionUnsubscribedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *SessionUnsubscribedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionUnsubscribedRequest) GetTopic() string {
+	if x != nil {
+		return x.Topic
+	}
+	return ""
+}
+
+func (x *SessionUnsubscribedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionResumedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionResumedRequest) Reset() {
+	*x = SessionResumedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[13]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionResumedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionResumedRequest) ProtoMessage() {}
+
+func (x *SessionResumedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[13]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionResumedRequest.ProtoReflect.Descriptor instead.
+func (*SessionResumedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *SessionResumedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionResumedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionDiscardedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionDiscardedRequest) Reset() {
+	*x = SessionDiscardedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[14]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionDiscardedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionDiscardedRequest) ProtoMessage() {}
+
+func (x *SessionDiscardedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[14]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionDiscardedRequest.ProtoReflect.Descriptor instead.
+func (*SessionDiscardedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *SessionDiscardedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionDiscardedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionTakenoverRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionTakenoverRequest) Reset() {
+	*x = SessionTakenoverRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[15]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionTakenoverRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionTakenoverRequest) ProtoMessage() {}
+
+func (x *SessionTakenoverRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[15]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionTakenoverRequest.ProtoReflect.Descriptor instead.
+func (*SessionTakenoverRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{15}
+}
+
+func (x *SessionTakenoverRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionTakenoverRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type SessionTerminatedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Reason     string       `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *SessionTerminatedRequest) Reset() {
+	*x = SessionTerminatedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[16]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SessionTerminatedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionTerminatedRequest) ProtoMessage() {}
+
+func (x *SessionTerminatedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[16]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionTerminatedRequest.ProtoReflect.Descriptor instead.
+func (*SessionTerminatedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{16}
+}
+
+func (x *SessionTerminatedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *SessionTerminatedRequest) GetReason() string {
+	if x != nil {
+		return x.Reason
+	}
+	return ""
+}
+
+func (x *SessionTerminatedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type MessagePublishRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Message *Message     `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+	Meta    *RequestMeta `protobuf:"bytes,2,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *MessagePublishRequest) Reset() {
+	*x = MessagePublishRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[17]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MessagePublishRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MessagePublishRequest) ProtoMessage() {}
+
+func (x *MessagePublishRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[17]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MessagePublishRequest.ProtoReflect.Descriptor instead.
+func (*MessagePublishRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{17}
+}
+
+func (x *MessagePublishRequest) GetMessage() *Message {
+	if x != nil {
+		return x.Message
+	}
+	return nil
+}
+
+func (x *MessagePublishRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type MessageDeliveredRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Message    *Message     `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *MessageDeliveredRequest) Reset() {
+	*x = MessageDeliveredRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[18]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MessageDeliveredRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MessageDeliveredRequest) ProtoMessage() {}
+
+func (x *MessageDeliveredRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[18]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MessageDeliveredRequest.ProtoReflect.Descriptor instead.
+func (*MessageDeliveredRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{18}
+}
+
+func (x *MessageDeliveredRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *MessageDeliveredRequest) GetMessage() *Message {
+	if x != nil {
+		return x.Message
+	}
+	return nil
+}
+
+func (x *MessageDeliveredRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type MessageDroppedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Message *Message     `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+	Reason  string       `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"`
+	Meta    *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *MessageDroppedRequest) Reset() {
+	*x = MessageDroppedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[19]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MessageDroppedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MessageDroppedRequest) ProtoMessage() {}
+
+func (x *MessageDroppedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[19]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MessageDroppedRequest.ProtoReflect.Descriptor instead.
+func (*MessageDroppedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{19}
+}
+
+func (x *MessageDroppedRequest) GetMessage() *Message {
+	if x != nil {
+		return x.Message
+	}
+	return nil
+}
+
+func (x *MessageDroppedRequest) GetReason() string {
+	if x != nil {
+		return x.Reason
+	}
+	return ""
+}
+
+func (x *MessageDroppedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type MessageAckedRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Clientinfo *ClientInfo  `protobuf:"bytes,1,opt,name=clientinfo,proto3" json:"clientinfo,omitempty"`
+	Message    *Message     `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
+	Meta       *RequestMeta `protobuf:"bytes,3,opt,name=meta,proto3" json:"meta,omitempty"`
+}
+
+func (x *MessageAckedRequest) Reset() {
+	*x = MessageAckedRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[20]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MessageAckedRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MessageAckedRequest) ProtoMessage() {}
+
+func (x *MessageAckedRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[20]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MessageAckedRequest.ProtoReflect.Descriptor instead.
+func (*MessageAckedRequest) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{20}
+}
+
+func (x *MessageAckedRequest) GetClientinfo() *ClientInfo {
+	if x != nil {
+		return x.Clientinfo
+	}
+	return nil
+}
+
+func (x *MessageAckedRequest) GetMessage() *Message {
+	if x != nil {
+		return x.Message
+	}
+	return nil
+}
+
+func (x *MessageAckedRequest) GetMeta() *RequestMeta {
+	if x != nil {
+		return x.Meta
+	}
+	return nil
+}
+
+type LoadedResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Hooks []*HookSpec `protobuf:"bytes,1,rep,name=hooks,proto3" json:"hooks,omitempty"`
+}
+
+func (x *LoadedResponse) Reset() {
+	*x = LoadedResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[21]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *LoadedResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LoadedResponse) ProtoMessage() {}
+
+func (x *LoadedResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[21]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use LoadedResponse.ProtoReflect.Descriptor instead.
+func (*LoadedResponse) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *LoadedResponse) GetHooks() []*HookSpec {
+	if x != nil {
+		return x.Hooks
+	}
+	return nil
+}
+
+type ValuedResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Type ValuedResponse_ResponsedType `protobuf:"varint,1,opt,name=type,proto3,enum=emqx.exhook.v2.ValuedResponse_ResponsedType" json:"type,omitempty"`
+	// Types that are assignable to Value:
+	//	*ValuedResponse_BoolResult
+	//	*ValuedResponse_Message
+	Value isValuedResponse_Value `protobuf_oneof:"value"`
+}
+
+func (x *ValuedResponse) Reset() {
+	*x = ValuedResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[22]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ValuedResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValuedResponse) ProtoMessage() {}
+
+func (x *ValuedResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[22]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValuedResponse.ProtoReflect.Descriptor instead.
+func (*ValuedResponse) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{22}
+}
+
+func (x *ValuedResponse) GetType() ValuedResponse_ResponsedType {
+	if x != nil {
+		return x.Type
+	}
+	return ValuedResponse_CONTINUE
+}
+
+func (m *ValuedResponse) GetValue() isValuedResponse_Value {
+	if m != nil {
+		return m.Value
+	}
+	return nil
+}
+
+func (x *ValuedResponse) GetBoolResult() bool {
+	if x, ok := x.GetValue().(*ValuedResponse_BoolResult); ok {
+		return x.BoolResult
+	}
+	return false
+}
+
+func (x *ValuedResponse) GetMessage() *Message {
+	if x, ok := x.GetValue().(*ValuedResponse_Message); ok {
+		return x.Message
+	}
+	return nil
+}
+
+type isValuedResponse_Value interface {
+	isValuedResponse_Value()
+}
+
+type ValuedResponse_BoolResult struct {
+	// Boolean result, used on the 'client.authenticate', 'client.authorize' hooks
+	BoolResult bool `protobuf:"varint,3,opt,name=bool_result,json=boolResult,proto3,oneof"`
+}
+
+type ValuedResponse_Message struct {
+	// Message result, used on the 'message.*' hooks
+	Message *Message `protobuf:"bytes,4,opt,name=message,proto3,oneof"`
+}
+
+func (*ValuedResponse_BoolResult) isValuedResponse_Value() {}
+
+func (*ValuedResponse_Message) isValuedResponse_Value() {}
+
+type EmptySuccess struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *EmptySuccess) Reset() {
+	*x = EmptySuccess{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[23]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *EmptySuccess) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EmptySuccess) ProtoMessage() {}
+
+func (x *EmptySuccess) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[23]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use EmptySuccess.ProtoReflect.Descriptor instead.
+func (*EmptySuccess) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{23}
+}
+
+type BrokerInfo struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Version  string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
+	Sysdescr string `protobuf:"bytes,2,opt,name=sysdescr,proto3" json:"sysdescr,omitempty"`
+	Uptime   int64  `protobuf:"varint,3,opt,name=uptime,proto3" json:"uptime,omitempty"`
+	Datetime string `protobuf:"bytes,4,opt,name=datetime,proto3" json:"datetime,omitempty"`
+}
+
+func (x *BrokerInfo) Reset() {
+	*x = BrokerInfo{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[24]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *BrokerInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BrokerInfo) ProtoMessage() {}
+
+func (x *BrokerInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[24]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BrokerInfo.ProtoReflect.Descriptor instead.
+func (*BrokerInfo) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{24}
+}
+
+func (x *BrokerInfo) GetVersion() string {
+	if x != nil {
+		return x.Version
+	}
+	return ""
+}
+
+func (x *BrokerInfo) GetSysdescr() string {
+	if x != nil {
+		return x.Sysdescr
+	}
+	return ""
+}
+
+func (x *BrokerInfo) GetUptime() int64 {
+	if x != nil {
+		return x.Uptime
+	}
+	return 0
+}
+
+func (x *BrokerInfo) GetDatetime() string {
+	if x != nil {
+		return x.Datetime
+	}
+	return ""
+}
+
+type HookSpec struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The registered hooks name
+	//
+	// Available value:
+	//   "client.connect",      "client.connack"
+	//   "client.connected",    "client.disconnected"
+	//   "client.authenticate", "client.authorize"
+	//   "client.subscribe",    "client.unsubscribe"
+	//
+	//   "session.created",      "session.subscribed"
+	//   "session.unsubscribed", "session.resumed"
+	//   "session.discarded",    "session.takenover"
+	//   "session.terminated"
+	//
+	//   "message.publish", "message.delivered"
+	//   "message.acked",   "message.dropped"
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	// The topic filters for message hooks
+	Topics []string `protobuf:"bytes,2,rep,name=topics,proto3" json:"topics,omitempty"`
+}
+
+func (x *HookSpec) Reset() {
+	*x = HookSpec{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[25]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *HookSpec) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*HookSpec) ProtoMessage() {}
+
+func (x *HookSpec) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[25]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use HookSpec.ProtoReflect.Descriptor instead.
+func (*HookSpec) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{25}
+}
+
+func (x *HookSpec) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *HookSpec) GetTopics() []string {
+	if x != nil {
+		return x.Topics
+	}
+	return nil
+}
+
+type ConnInfo struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Node      string `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+	Clientid  string `protobuf:"bytes,2,opt,name=clientid,proto3" json:"clientid,omitempty"`
+	Username  string `protobuf:"bytes,3,opt,name=username,proto3" json:"username,omitempty"`
+	Peerhost  string `protobuf:"bytes,4,opt,name=peerhost,proto3" json:"peerhost,omitempty"`
+	Sockport  uint32 `protobuf:"varint,5,opt,name=sockport,proto3" json:"sockport,omitempty"`
+	ProtoName string `protobuf:"bytes,6,opt,name=proto_name,json=protoName,proto3" json:"proto_name,omitempty"`
+	ProtoVer  string `protobuf:"bytes,7,opt,name=proto_ver,json=protoVer,proto3" json:"proto_ver,omitempty"`
+	Keepalive uint32 `protobuf:"varint,8,opt,name=keepalive,proto3" json:"keepalive,omitempty"`
+}
+
+func (x *ConnInfo) Reset() {
+	*x = ConnInfo{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[26]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ConnInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ConnInfo) ProtoMessage() {}
+
+func (x *ConnInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[26]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ConnInfo.ProtoReflect.Descriptor instead.
+func (*ConnInfo) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{26}
+}
+
+func (x *ConnInfo) GetNode() string {
+	if x != nil {
+		return x.Node
+	}
+	return ""
+}
+
+func (x *ConnInfo) GetClientid() string {
+	if x != nil {
+		return x.Clientid
+	}
+	return ""
+}
+
+func (x *ConnInfo) GetUsername() string {
+	if x != nil {
+		return x.Username
+	}
+	return ""
+}
+
+func (x *ConnInfo) GetPeerhost() string {
+	if x != nil {
+		return x.Peerhost
+	}
+	return ""
+}
+
+func (x *ConnInfo) GetSockport() uint32 {
+	if x != nil {
+		return x.Sockport
+	}
+	return 0
+}
+
+func (x *ConnInfo) GetProtoName() string {
+	if x != nil {
+		return x.ProtoName
+	}
+	return ""
+}
+
+func (x *ConnInfo) GetProtoVer() string {
+	if x != nil {
+		return x.ProtoVer
+	}
+	return ""
+}
+
+func (x *ConnInfo) GetKeepalive() uint32 {
+	if x != nil {
+		return x.Keepalive
+	}
+	return 0
+}
+
+type ClientInfo struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Node        string `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+	Clientid    string `protobuf:"bytes,2,opt,name=clientid,proto3" json:"clientid,omitempty"`
+	Username    string `protobuf:"bytes,3,opt,name=username,proto3" json:"username,omitempty"`
+	Password    string `protobuf:"bytes,4,opt,name=password,proto3" json:"password,omitempty"`
+	Peerhost    string `protobuf:"bytes,5,opt,name=peerhost,proto3" json:"peerhost,omitempty"`
+	Sockport    uint32 `protobuf:"varint,6,opt,name=sockport,proto3" json:"sockport,omitempty"`
+	Protocol    string `protobuf:"bytes,7,opt,name=protocol,proto3" json:"protocol,omitempty"`
+	Mountpoint  string `protobuf:"bytes,8,opt,name=mountpoint,proto3" json:"mountpoint,omitempty"`
+	IsSuperuser bool   `protobuf:"varint,9,opt,name=is_superuser,json=isSuperuser,proto3" json:"is_superuser,omitempty"`
+	Anonymous   bool   `protobuf:"varint,10,opt,name=anonymous,proto3" json:"anonymous,omitempty"`
+	// common name of client TLS cert
+	Cn string `protobuf:"bytes,11,opt,name=cn,proto3" json:"cn,omitempty"`
+	// subject of client TLS cert
+	Dn string `protobuf:"bytes,12,opt,name=dn,proto3" json:"dn,omitempty"`
+}
+
+func (x *ClientInfo) Reset() {
+	*x = ClientInfo{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[27]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ClientInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ClientInfo) ProtoMessage() {}
+
+func (x *ClientInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[27]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ClientInfo.ProtoReflect.Descriptor instead.
+func (*ClientInfo) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{27}
+}
+
+func (x *ClientInfo) GetNode() string {
+	if x != nil {
+		return x.Node
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetClientid() string {
+	if x != nil {
+		return x.Clientid
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetUsername() string {
+	if x != nil {
+		return x.Username
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetPassword() string {
+	if x != nil {
+		return x.Password
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetPeerhost() string {
+	if x != nil {
+		return x.Peerhost
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetSockport() uint32 {
+	if x != nil {
+		return x.Sockport
+	}
+	return 0
+}
+
+func (x *ClientInfo) GetProtocol() string {
+	if x != nil {
+		return x.Protocol
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetMountpoint() string {
+	if x != nil {
+		return x.Mountpoint
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetIsSuperuser() bool {
+	if x != nil {
+		return x.IsSuperuser
+	}
+	return false
+}
+
+func (x *ClientInfo) GetAnonymous() bool {
+	if x != nil {
+		return x.Anonymous
+	}
+	return false
+}
+
+func (x *ClientInfo) GetCn() string {
+	if x != nil {
+		return x.Cn
+	}
+	return ""
+}
+
+func (x *ClientInfo) GetDn() string {
+	if x != nil {
+		return x.Dn
+	}
+	return ""
+}
+
+type Message struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Node      string `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+	Id        string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
+	Qos       uint32 `protobuf:"varint,3,opt,name=qos,proto3" json:"qos,omitempty"`
+	From      string `protobuf:"bytes,4,opt,name=from,proto3" json:"from,omitempty"`
+	Topic     string `protobuf:"bytes,5,opt,name=topic,proto3" json:"topic,omitempty"`
+	Payload   []byte `protobuf:"bytes,6,opt,name=payload,proto3" json:"payload,omitempty"`
+	Timestamp uint64 `protobuf:"varint,7,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	// The key of header can be:
+	//  - username:
+	//    * Readonly
+	//    * The username of sender client
+	//    * Value type: utf8 string
+	//  - protocol:
+	//    * Readonly
+	//    * The protocol name of sender client
+	//    * Value type: string enum with "mqtt", "mqtt-sn", ...
+	//  - peerhost:
+	//    * Readonly
+	//    * The peerhost of sender client
+	//    * Value type: ip address string
+	//  - allow_publish:
+	//    * Writable
+	//    * Whether to allow the message to be published by emqx
+	//    * Value type: string enum with "true", "false", default is "true"
+	//
+	// Notes: All header may be missing, which means that the message does not
+	//   carry these headers. We can guarantee that clients coming from MQTT,
+	//   MQTT-SN, CoAP, LwM2M and other natively supported protocol clients will
+	//   carry these headers, but there is no guarantee that messages published
+	//   by other means will do, e.g. messages published by HTTP-API
+	Headers map[string]string `protobuf:"bytes,8,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *Message) Reset() {
+	*x = Message{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[28]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Message) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Message) ProtoMessage() {}
+
+func (x *Message) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[28]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Message.ProtoReflect.Descriptor instead.
+func (*Message) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{28}
+}
+
+func (x *Message) GetNode() string {
+	if x != nil {
+		return x.Node
+	}
+	return ""
+}
+
+func (x *Message) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
+func (x *Message) GetQos() uint32 {
+	if x != nil {
+		return x.Qos
+	}
+	return 0
+}
+
+func (x *Message) GetFrom() string {
+	if x != nil {
+		return x.From
+	}
+	return ""
+}
+
+func (x *Message) GetTopic() string {
+	if x != nil {
+		return x.Topic
+	}
+	return ""
+}
+
+func (x *Message) GetPayload() []byte {
+	if x != nil {
+		return x.Payload
+	}
+	return nil
+}
+
+func (x *Message) GetTimestamp() uint64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *Message) GetHeaders() map[string]string {
+	if x != nil {
+		return x.Headers
+	}
+	return nil
+}
+
+type Property struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name  string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
+}
+
+func (x *Property) Reset() {
+	*x = Property{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[29]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Property) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Property) ProtoMessage() {}
+
+func (x *Property) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[29]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Property.ProtoReflect.Descriptor instead.
+func (*Property) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{29}
+}
+
+func (x *Property) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *Property) GetValue() string {
+	if x != nil {
+		return x.Value
+	}
+	return ""
+}
+
+type TopicFilter struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Qos  uint32 `protobuf:"varint,2,opt,name=qos,proto3" json:"qos,omitempty"`
+}
+
+func (x *TopicFilter) Reset() {
+	*x = TopicFilter{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[30]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TopicFilter) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TopicFilter) ProtoMessage() {}
+
+func (x *TopicFilter) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[30]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use TopicFilter.ProtoReflect.Descriptor instead.
+func (*TopicFilter) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{30}
+}
+
+func (x *TopicFilter) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *TopicFilter) GetQos() uint32 {
+	if x != nil {
+		return x.Qos
+	}
+	return 0
+}
+
+type SubOpts struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The QoS level
+	Qos uint32 `protobuf:"varint,1,opt,name=qos,proto3" json:"qos,omitempty"`
+	// The group name for shared subscription
+	Share string `protobuf:"bytes,2,opt,name=share,proto3" json:"share,omitempty"`
+	// The Retain Handling option (MQTT v5.0)
+	//
+	//  0 = Send retained messages at the time of the subscribe
+	//  1 = Send retained messages at subscribe only if the subscription does
+	//       not currently exist
+	//  2 = Do not send retained messages at the time of the subscribe
+	Rh uint32 `protobuf:"varint,3,opt,name=rh,proto3" json:"rh,omitempty"`
+	// The Retain as Published option (MQTT v5.0)
+	//
+	//  If 1, Application Messages forwarded using this subscription keep the
+	//        RETAIN flag they were published with.
+	//  If 0, Application Messages forwarded using this subscription have the
+	//        RETAIN flag set to 0.
+	// Retained messages sent when the subscription is established have the RETAIN flag set to 1.
+	Rap uint32 `protobuf:"varint,4,opt,name=rap,proto3" json:"rap,omitempty"`
+	// The No Local option (MQTT v5.0)
+	//
+	// If the value is 1, Application Messages MUST NOT be forwarded to a
+	// connection with a ClientID equal to the ClientID of the publishing
+	Nl uint32 `protobuf:"varint,5,opt,name=nl,proto3" json:"nl,omitempty"`
+}
+
+func (x *SubOpts) Reset() {
+	*x = SubOpts{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[31]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SubOpts) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubOpts) ProtoMessage() {}
+
+func (x *SubOpts) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[31]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SubOpts.ProtoReflect.Descriptor instead.
+func (*SubOpts) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{31}
+}
+
+func (x *SubOpts) GetQos() uint32 {
+	if x != nil {
+		return x.Qos
+	}
+	return 0
+}
+
+func (x *SubOpts) GetShare() string {
+	if x != nil {
+		return x.Share
+	}
+	return ""
+}
+
+func (x *SubOpts) GetRh() uint32 {
+	if x != nil {
+		return x.Rh
+	}
+	return 0
+}
+
+func (x *SubOpts) GetRap() uint32 {
+	if x != nil {
+		return x.Rap
+	}
+	return 0
+}
+
+func (x *SubOpts) GetNl() uint32 {
+	if x != nil {
+		return x.Nl
+	}
+	return 0
+}
+
+type RequestMeta struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Node        string `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+	Version     string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
+	Sysdescr    string `protobuf:"bytes,3,opt,name=sysdescr,proto3" json:"sysdescr,omitempty"`
+	ClusterName string `protobuf:"bytes,4,opt,name=cluster_name,json=clusterName,proto3" json:"cluster_name,omitempty"`
+}
+
+func (x *RequestMeta) Reset() {
+	*x = RequestMeta{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_protobuf_exhook_proto_msgTypes[32]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *RequestMeta) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RequestMeta) ProtoMessage() {}
+
+func (x *RequestMeta) ProtoReflect() protoreflect.Message {
+	mi := &file_protobuf_exhook_proto_msgTypes[32]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RequestMeta.ProtoReflect.Descriptor instead.
+func (*RequestMeta) Descriptor() ([]byte, []int) {
+	return file_protobuf_exhook_proto_rawDescGZIP(), []int{32}
+}
+
+func (x *RequestMeta) GetNode() string {
+	if x != nil {
+		return x.Node
+	}
+	return ""
+}
+
+func (x *RequestMeta) GetVersion() string {
+	if x != nil {
+		return x.Version
+	}
+	return ""
+}
+
+func (x *RequestMeta) GetSysdescr() string {
+	if x != nil {
+		return x.Sysdescr
+	}
+	return ""
+}
+
+func (x *RequestMeta) GetClusterName() string {
+	if x != nil {
+		return x.ClusterName
+	}
+	return ""
+}
+
+var File_protobuf_exhook_proto protoreflect.FileDescriptor
+
+var file_protobuf_exhook_proto_rawDesc = []byte{
+	0x0a, 0x15, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x78, 0x68, 0x6f, 0x6f,
+	0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x22, 0x7c, 0x0a, 0x15, 0x50, 0x72, 0x6f, 0x76, 0x69,
+	0x64, 0x65, 0x72, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x12, 0x32, 0x0a, 0x06, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76,
+	0x32, 0x2e, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x62, 0x72,
+	0x6f, 0x6b, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52,
+	0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x4a, 0x0a, 0x17, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
+	0x72, 0x55, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74,
+	0x61, 0x22, 0xad, 0x01, 0x0a, 0x14, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e,
+	0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x08, 0x63, 0x6f,
+	0x6e, 0x6e, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65,
+	0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f,
+	0x6e, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x6e, 0x69, 0x6e, 0x66, 0x6f,
+	0x12, 0x2e, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x18, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73,
+	0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74,
+	0x61, 0x22, 0xce, 0x01, 0x0a, 0x14, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e,
+	0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x08, 0x63, 0x6f,
+	0x6e, 0x6e, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65,
+	0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f,
+	0x6e, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x6e, 0x69, 0x6e, 0x66, 0x6f,
+	0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x64,
+	0x65, 0x12, 0x2e, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x18, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76,
+	0x32, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x70,
+	0x73, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65,
+	0x74, 0x61, 0x22, 0x85, 0x01, 0x0a, 0x16, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e,
+	0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a,
+	0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e,
+	0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74,
+	0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65,
+	0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0xa0, 0x01, 0x0a, 0x19, 0x43,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65,
+	0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65,
+	0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c,
+	0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
+	0x69, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x04,
+	0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0xa0, 0x01,
+	0x0a, 0x19, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69,
+	0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c,
+	0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12,
+	0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
+	0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61,
+	0x22, 0xb0, 0x02, 0x0a, 0x16, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f,
+	0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x4b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x37, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68,
+	0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74,
+	0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x75,
+	0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04,
+	0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65,
+	0x73, 0x75, 0x6c, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75,
+	0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76,
+	0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d,
+	0x65, 0x74, 0x61, 0x22, 0x2e, 0x0a, 0x10, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65,
+	0x52, 0x65, 0x71, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x55, 0x42, 0x4c, 0x49,
+	0x53, 0x48, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42,
+	0x45, 0x10, 0x01, 0x22, 0xf7, 0x01, 0x0a, 0x16, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x75,
+	0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a,
+	0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a,
+	0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x05, 0x70, 0x72,
+	0x6f, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x6d, 0x71, 0x78,
+	0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65,
+	0x72, 0x74, 0x79, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x12, 0x40, 0x0a, 0x0d, 0x74, 0x6f,
+	0x70, 0x69, 0x63, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e,
+	0x76, 0x32, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0c,
+	0x74, 0x6f, 0x70, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x0a, 0x04,
+	0x6d, 0x65, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0xf9, 0x01,
+	0x0a, 0x18, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72,
+	0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c,
+	0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x18,
+	0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68,
+	0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52,
+	0x05, 0x70, 0x72, 0x6f, 0x70, 0x73, 0x12, 0x40, 0x0a, 0x0d, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x5f,
+	0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
+	0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x54,
+	0x6f, 0x70, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0c, 0x74, 0x6f, 0x70, 0x69,
+	0x63, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,
+	0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x84, 0x01, 0x0a, 0x15, 0x53, 0x65,
+	0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66,
+	0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65,
+	0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49,
+	0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12,
+	0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
+	0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61,
+	0x22, 0xd0, 0x01, 0x0a, 0x18, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x75, 0x62, 0x73,
+	0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a,
+	0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e,
+	0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70,
+	0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12,
+	0x31, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6f, 0x70, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x17, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76,
+	0x32, 0x2e, 0x53, 0x75, 0x62, 0x4f, 0x70, 0x74, 0x73, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6f, 0x70,
+	0x74, 0x73, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76,
+	0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d,
+	0x65, 0x74, 0x61, 0x22, 0x9f, 0x01, 0x0a, 0x1a, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x55,
+	0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e,
+	0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x14,
+	0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74,
+	0x6f, 0x70, 0x69, 0x63, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52,
+	0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x84, 0x01, 0x0a, 0x15, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
+	0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+	0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f,
+	0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52,
+	0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x0a, 0x04, 0x6d,
+	0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78,
+	0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x86, 0x01, 0x0a,
+	0x17, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x65,
+	0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65,
+	0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c,
+	0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
+	0x69, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52,
+	0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x86, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
+	0x6e, 0x54, 0x61, 0x6b, 0x65, 0x6e, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68,
+	0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66,
+	0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x0a,
+	0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d,
+	0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x9f,
+	0x01, 0x0a, 0x18, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e,
+	0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x1a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f,
+	0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12,
+	0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
+	0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61,
+	0x22, 0x7b, 0x0a, 0x15, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69,
+	0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x07, 0x6d, 0x65, 0x73,
+	0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x04,
+	0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0xb9, 0x01,
+	0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72,
+	0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
+	0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x31, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
+	0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,
+	0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x93, 0x01, 0x0a, 0x15, 0x4d, 0x65,
+	0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d,
+	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x2f,
+	0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65,
+	0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22,
+	0xb5, 0x01, 0x0a, 0x13, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x41, 0x63, 0x6b, 0x65, 0x64,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x6d,
+	0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69,
+	0x6e, 0x66, 0x6f, 0x12, 0x31, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d,
+	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74,
+	0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x40, 0x0a, 0x0e, 0x4c, 0x6f, 0x61, 0x64, 0x65,
+	0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x05, 0x68, 0x6f, 0x6f,
+	0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e,
+	0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x48, 0x6f, 0x6f, 0x6b, 0x53, 0x70,
+	0x65, 0x63, 0x52, 0x05, 0x68, 0x6f, 0x6f, 0x6b, 0x73, 0x22, 0xf3, 0x01, 0x0a, 0x0e, 0x56, 0x61,
+	0x6c, 0x75, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x04,
+	0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x56, 0x61, 0x6c, 0x75,
+	0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x21,
+	0x0a, 0x0b, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x75, 0x6c,
+	0x74, 0x12, 0x33, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x17, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x07, 0x6d,
+	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x3e, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x4f, 0x4e, 0x54, 0x49,
+	0x4e, 0x55, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45, 0x10,
+	0x01, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x54, 0x4f, 0x50, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x52, 0x45,
+	0x54, 0x55, 0x52, 0x4e, 0x10, 0x02, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,
+	0x0e, 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22,
+	0x76, 0x0a, 0x0a, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a,
+	0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
+	0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x79, 0x73, 0x64, 0x65,
+	0x73, 0x63, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x79, 0x73, 0x64, 0x65,
+	0x73, 0x63, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x64,
+	0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64,
+	0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x36, 0x0a, 0x08, 0x48, 0x6f, 0x6f, 0x6b, 0x53,
+	0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63,
+	0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x22,
+	0xe8, 0x01, 0x0a, 0x08, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04,
+	0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65,
+	0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08,
+	0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+	0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x65, 0x65, 0x72,
+	0x68, 0x6f, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x65, 0x65, 0x72,
+	0x68, 0x6f, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6f, 0x63, 0x6b, 0x70, 0x6f, 0x72, 0x74,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x6f, 0x63, 0x6b, 0x70, 0x6f, 0x72, 0x74,
+	0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x4e, 0x61, 0x6d, 0x65, 0x12,
+	0x1b, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x56, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09,
+	0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52,
+	0x09, 0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x22, 0xc9, 0x02, 0x0a, 0x0a, 0x43,
+	0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x64,
+	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a,
+	0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65,
+	0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65,
+	0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
+	0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
+	0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x65, 0x65, 0x72, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x65, 0x65, 0x72, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1a, 0x0a,
+	0x08, 0x73, 0x6f, 0x63, 0x6b, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52,
+	0x08, 0x73, 0x6f, 0x63, 0x6b, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x70, 0x6f,
+	0x69, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
+	0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x65,
+	0x72, 0x75, 0x73, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x53,
+	0x75, 0x70, 0x65, 0x72, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x6e, 0x6f, 0x6e,
+	0x79, 0x6d, 0x6f, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x61, 0x6e, 0x6f,
+	0x6e, 0x79, 0x6d, 0x6f, 0x75, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x63, 0x6e, 0x18, 0x0b, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x02, 0x63, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x64, 0x6e, 0x18, 0x0c, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x02, 0x64, 0x6e, 0x22, 0x9d, 0x02, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x71, 0x6f, 0x73, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x0d, 0x52, 0x03, 0x71, 0x6f, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x14, 0x0a, 0x05,
+	0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70,
+	0x69, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x06, 0x20,
+	0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1c, 0x0a, 0x09,
+	0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3e, 0x0a, 0x07, 0x68, 0x65,
+	0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x65, 0x6d,
+	0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73,
+	0x73, 0x61, 0x67, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65,
+	0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
+	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
+	0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x34, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72,
+	0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x33, 0x0a, 0x0b,
+	0x54, 0x6f, 0x70, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e,
+	0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
+	0x10, 0x0a, 0x03, 0x71, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x71, 0x6f,
+	0x73, 0x22, 0x63, 0x0a, 0x07, 0x53, 0x75, 0x62, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03,
+	0x71, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x71, 0x6f, 0x73, 0x12, 0x14,
+	0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73,
+	0x68, 0x61, 0x72, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x72, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d,
+	0x52, 0x02, 0x72, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x61, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28,
+	0x0d, 0x52, 0x03, 0x72, 0x61, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x6e, 0x6c, 0x18, 0x05, 0x20, 0x01,
+	0x28, 0x0d, 0x52, 0x02, 0x6e, 0x6c, 0x22, 0x7a, 0x0a, 0x0b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72,
+	0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
+	0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x79, 0x73, 0x64, 0x65, 0x73, 0x63, 0x72, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x79, 0x73, 0x64, 0x65, 0x73, 0x63, 0x72, 0x12,
+	0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+	0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61,
+	0x6d, 0x65, 0x32, 0xc7, 0x0f, 0x0a, 0x0c, 0x48, 0x6f, 0x6f, 0x6b, 0x50, 0x72, 0x6f, 0x76, 0x69,
+	0x64, 0x65, 0x72, 0x12, 0x5b, 0x0a, 0x10, 0x4f, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
+	0x72, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x12, 0x25, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65,
+	0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
+	0x72, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x4c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
+	0x12, 0x5d, 0x0a, 0x12, 0x4f, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x55, 0x6e,
+	0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x12, 0x27, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
+	0x55, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12,
+	0x57, 0x0a, 0x0f, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
+	0x63, 0x74, 0x12, 0x24, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
+	0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e,
+	0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53,
+	0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x57, 0x0a, 0x0f, 0x4f, 0x6e, 0x43, 0x6c,
+	0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x61, 0x63, 0x6b, 0x12, 0x24, 0x2e, 0x65, 0x6d,
+	0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e,
+	0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22,
+	0x00, 0x12, 0x5b, 0x0a, 0x11, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e,
+	0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x26, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f,
+	0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x61,
+	0x0a, 0x14, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e,
+	0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x29, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x44, 0x69,
+	0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e,
+	0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22,
+	0x00, 0x12, 0x63, 0x0a, 0x14, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74,
+	0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x29, 0x2e, 0x65, 0x6d, 0x71, 0x78,
+	0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x11, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x12, 0x26, 0x2e, 0x65, 0x6d,
+	0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f,
+	0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x11, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x26, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65,
+	0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73,
+	0x22, 0x00, 0x12, 0x5f, 0x0a, 0x13, 0x4f, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x6e,
+	0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x28, 0x2e, 0x65, 0x6d, 0x71, 0x78,
+	0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e,
+	0x74, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f,
+	0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73,
+	0x73, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x10, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
+	0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x25, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65,
+	0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
+	0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x5f,
+	0x0a, 0x13, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x75, 0x62, 0x73, 0x63,
+	0x72, 0x69, 0x62, 0x65, 0x64, 0x12, 0x28, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68,
+	0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x75,
+	0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12,
+	0x63, 0x0a, 0x15, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x73, 0x75,
+	0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x12, 0x2a, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e,
+	0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
+	0x6e, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65,
+	0x73, 0x73, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x10, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
+	0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x12, 0x25, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e,
+	0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
+	0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32,
+	0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12,
+	0x5d, 0x0a, 0x12, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x69, 0x73, 0x63,
+	0x61, 0x72, 0x64, 0x65, 0x64, 0x12, 0x27, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68,
+	0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x69,
+	0x73, 0x63, 0x61, 0x72, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x5d,
+	0x0a, 0x12, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x61, 0x6b, 0x65, 0x6e,
+	0x6f, 0x76, 0x65, 0x72, 0x12, 0x27, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x61, 0x6b,
+	0x65, 0x6e, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e,
+	0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45,
+	0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x5f, 0x0a,
+	0x13, 0x4f, 0x6e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e,
+	0x61, 0x74, 0x65, 0x64, 0x12, 0x28, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f,
+	0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x65, 0x72,
+	0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x5b,
+	0x0a, 0x10, 0x4f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69,
+	0x73, 0x68, 0x12, 0x25, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b,
+	0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69,
+	0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x65, 0x6d, 0x71, 0x78,
+	0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65,
+	0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x12, 0x4f,
+	0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x65,
+	0x64, 0x12, 0x27, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e,
+	0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65,
+	0x72, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71,
+	0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74,
+	0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x10, 0x4f, 0x6e,
+	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x12, 0x25,
+	0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e,
+	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68,
+	0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63,
+	0x65, 0x73, 0x73, 0x22, 0x00, 0x12, 0x55, 0x0a, 0x0e, 0x4f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x41, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x23, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65,
+	0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x41, 0x63, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65,
+	0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x6d,
+	0x70, 0x74, 0x79, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x00, 0x42, 0x49, 0x0a, 0x0e,
+	0x69, 0x6f, 0x2e, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0x42, 0x0f,
+	0x45, 0x6d, 0x71, 0x78, 0x45, 0x78, 0x48, 0x6f, 0x6f, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50,
+	0x01, 0x5a, 0x13, 0x65, 0x6d, 0x71, 0x78, 0x2e, 0x69, 0x6f, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f,
+	0x65, 0x78, 0x68, 0x6f, 0x6f, 0x6b, 0xaa, 0x02, 0x0e, 0x45, 0x6d, 0x71, 0x78, 0x2e, 0x45, 0x78,
+	0x68, 0x6f, 0x6f, 0x6b, 0x2e, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_protobuf_exhook_proto_rawDescOnce sync.Once
+	file_protobuf_exhook_proto_rawDescData = file_protobuf_exhook_proto_rawDesc
+)
+
+func file_protobuf_exhook_proto_rawDescGZIP() []byte {
+	file_protobuf_exhook_proto_rawDescOnce.Do(func() {
+		file_protobuf_exhook_proto_rawDescData = protoimpl.X.CompressGZIP(file_protobuf_exhook_proto_rawDescData)
+	})
+	return file_protobuf_exhook_proto_rawDescData
+}
+
+var file_protobuf_exhook_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_protobuf_exhook_proto_msgTypes = make([]protoimpl.MessageInfo, 34)
+var file_protobuf_exhook_proto_goTypes = []interface{}{
+	(ClientAuthorizeRequest_AuthorizeReqType)(0), // 0: emqx.exhook.v2.ClientAuthorizeRequest.AuthorizeReqType
+	(ValuedResponse_ResponsedType)(0),            // 1: emqx.exhook.v2.ValuedResponse.ResponsedType
+	(*ProviderLoadedRequest)(nil),                // 2: emqx.exhook.v2.ProviderLoadedRequest
+	(*ProviderUnloadedRequest)(nil),              // 3: emqx.exhook.v2.ProviderUnloadedRequest
+	(*ClientConnectRequest)(nil),                 // 4: emqx.exhook.v2.ClientConnectRequest
+	(*ClientConnackRequest)(nil),                 // 5: emqx.exhook.v2.ClientConnackRequest
+	(*ClientConnectedRequest)(nil),               // 6: emqx.exhook.v2.ClientConnectedRequest
+	(*ClientDisconnectedRequest)(nil),            // 7: emqx.exhook.v2.ClientDisconnectedRequest
+	(*ClientAuthenticateRequest)(nil),            // 8: emqx.exhook.v2.ClientAuthenticateRequest
+	(*ClientAuthorizeRequest)(nil),               // 9: emqx.exhook.v2.ClientAuthorizeRequest
+	(*ClientSubscribeRequest)(nil),               // 10: emqx.exhook.v2.ClientSubscribeRequest
+	(*ClientUnsubscribeRequest)(nil),             // 11: emqx.exhook.v2.ClientUnsubscribeRequest
+	(*SessionCreatedRequest)(nil),                // 12: emqx.exhook.v2.SessionCreatedRequest
+	(*SessionSubscribedRequest)(nil),             // 13: emqx.exhook.v2.SessionSubscribedRequest
+	(*SessionUnsubscribedRequest)(nil),           // 14: emqx.exhook.v2.SessionUnsubscribedRequest
+	(*SessionResumedRequest)(nil),                // 15: emqx.exhook.v2.SessionResumedRequest
+	(*SessionDiscardedRequest)(nil),              // 16: emqx.exhook.v2.SessionDiscardedRequest
+	(*SessionTakenoverRequest)(nil),              // 17: emqx.exhook.v2.SessionTakenoverRequest
+	(*SessionTerminatedRequest)(nil),             // 18: emqx.exhook.v2.SessionTerminatedRequest
+	(*MessagePublishRequest)(nil),                // 19: emqx.exhook.v2.MessagePublishRequest
+	(*MessageDeliveredRequest)(nil),              // 20: emqx.exhook.v2.MessageDeliveredRequest
+	(*MessageDroppedRequest)(nil),                // 21: emqx.exhook.v2.MessageDroppedRequest
+	(*MessageAckedRequest)(nil),                  // 22: emqx.exhook.v2.MessageAckedRequest
+	(*LoadedResponse)(nil),                       // 23: emqx.exhook.v2.LoadedResponse
+	(*ValuedResponse)(nil),                       // 24: emqx.exhook.v2.ValuedResponse
+	(*EmptySuccess)(nil),                         // 25: emqx.exhook.v2.EmptySuccess
+	(*BrokerInfo)(nil),                           // 26: emqx.exhook.v2.BrokerInfo
+	(*HookSpec)(nil),                             // 27: emqx.exhook.v2.HookSpec
+	(*ConnInfo)(nil),                             // 28: emqx.exhook.v2.ConnInfo
+	(*ClientInfo)(nil),                           // 29: emqx.exhook.v2.ClientInfo
+	(*Message)(nil),                              // 30: emqx.exhook.v2.Message
+	(*Property)(nil),                             // 31: emqx.exhook.v2.Property
+	(*TopicFilter)(nil),                          // 32: emqx.exhook.v2.TopicFilter
+	(*SubOpts)(nil),                              // 33: emqx.exhook.v2.SubOpts
+	(*RequestMeta)(nil),                          // 34: emqx.exhook.v2.RequestMeta
+	nil,                                          // 35: emqx.exhook.v2.Message.HeadersEntry
+}
+var file_protobuf_exhook_proto_depIdxs = []int32{
+	26, // 0: emqx.exhook.v2.ProviderLoadedRequest.broker:type_name -> emqx.exhook.v2.BrokerInfo
+	34, // 1: emqx.exhook.v2.ProviderLoadedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	34, // 2: emqx.exhook.v2.ProviderUnloadedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	28, // 3: emqx.exhook.v2.ClientConnectRequest.conninfo:type_name -> emqx.exhook.v2.ConnInfo
+	31, // 4: emqx.exhook.v2.ClientConnectRequest.props:type_name -> emqx.exhook.v2.Property
+	34, // 5: emqx.exhook.v2.ClientConnectRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	28, // 6: emqx.exhook.v2.ClientConnackRequest.conninfo:type_name -> emqx.exhook.v2.ConnInfo
+	31, // 7: emqx.exhook.v2.ClientConnackRequest.props:type_name -> emqx.exhook.v2.Property
+	34, // 8: emqx.exhook.v2.ClientConnackRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 9: emqx.exhook.v2.ClientConnectedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 10: emqx.exhook.v2.ClientConnectedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 11: emqx.exhook.v2.ClientDisconnectedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 12: emqx.exhook.v2.ClientDisconnectedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 13: emqx.exhook.v2.ClientAuthenticateRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 14: emqx.exhook.v2.ClientAuthenticateRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 15: emqx.exhook.v2.ClientAuthorizeRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	0,  // 16: emqx.exhook.v2.ClientAuthorizeRequest.type:type_name -> emqx.exhook.v2.ClientAuthorizeRequest.AuthorizeReqType
+	34, // 17: emqx.exhook.v2.ClientAuthorizeRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 18: emqx.exhook.v2.ClientSubscribeRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	31, // 19: emqx.exhook.v2.ClientSubscribeRequest.props:type_name -> emqx.exhook.v2.Property
+	32, // 20: emqx.exhook.v2.ClientSubscribeRequest.topic_filters:type_name -> emqx.exhook.v2.TopicFilter
+	34, // 21: emqx.exhook.v2.ClientSubscribeRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 22: emqx.exhook.v2.ClientUnsubscribeRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	31, // 23: emqx.exhook.v2.ClientUnsubscribeRequest.props:type_name -> emqx.exhook.v2.Property
+	32, // 24: emqx.exhook.v2.ClientUnsubscribeRequest.topic_filters:type_name -> emqx.exhook.v2.TopicFilter
+	34, // 25: emqx.exhook.v2.ClientUnsubscribeRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 26: emqx.exhook.v2.SessionCreatedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 27: emqx.exhook.v2.SessionCreatedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 28: emqx.exhook.v2.SessionSubscribedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	33, // 29: emqx.exhook.v2.SessionSubscribedRequest.subopts:type_name -> emqx.exhook.v2.SubOpts
+	34, // 30: emqx.exhook.v2.SessionSubscribedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 31: emqx.exhook.v2.SessionUnsubscribedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 32: emqx.exhook.v2.SessionUnsubscribedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 33: emqx.exhook.v2.SessionResumedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 34: emqx.exhook.v2.SessionResumedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 35: emqx.exhook.v2.SessionDiscardedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 36: emqx.exhook.v2.SessionDiscardedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 37: emqx.exhook.v2.SessionTakenoverRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 38: emqx.exhook.v2.SessionTakenoverRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 39: emqx.exhook.v2.SessionTerminatedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	34, // 40: emqx.exhook.v2.SessionTerminatedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	30, // 41: emqx.exhook.v2.MessagePublishRequest.message:type_name -> emqx.exhook.v2.Message
+	34, // 42: emqx.exhook.v2.MessagePublishRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 43: emqx.exhook.v2.MessageDeliveredRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	30, // 44: emqx.exhook.v2.MessageDeliveredRequest.message:type_name -> emqx.exhook.v2.Message
+	34, // 45: emqx.exhook.v2.MessageDeliveredRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	30, // 46: emqx.exhook.v2.MessageDroppedRequest.message:type_name -> emqx.exhook.v2.Message
+	34, // 47: emqx.exhook.v2.MessageDroppedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	29, // 48: emqx.exhook.v2.MessageAckedRequest.clientinfo:type_name -> emqx.exhook.v2.ClientInfo
+	30, // 49: emqx.exhook.v2.MessageAckedRequest.message:type_name -> emqx.exhook.v2.Message
+	34, // 50: emqx.exhook.v2.MessageAckedRequest.meta:type_name -> emqx.exhook.v2.RequestMeta
+	27, // 51: emqx.exhook.v2.LoadedResponse.hooks:type_name -> emqx.exhook.v2.HookSpec
+	1,  // 52: emqx.exhook.v2.ValuedResponse.type:type_name -> emqx.exhook.v2.ValuedResponse.ResponsedType
+	30, // 53: emqx.exhook.v2.ValuedResponse.message:type_name -> emqx.exhook.v2.Message
+	35, // 54: emqx.exhook.v2.Message.headers:type_name -> emqx.exhook.v2.Message.HeadersEntry
+	2,  // 55: emqx.exhook.v2.HookProvider.OnProviderLoaded:input_type -> emqx.exhook.v2.ProviderLoadedRequest
+	3,  // 56: emqx.exhook.v2.HookProvider.OnProviderUnloaded:input_type -> emqx.exhook.v2.ProviderUnloadedRequest
+	4,  // 57: emqx.exhook.v2.HookProvider.OnClientConnect:input_type -> emqx.exhook.v2.ClientConnectRequest
+	5,  // 58: emqx.exhook.v2.HookProvider.OnClientConnack:input_type -> emqx.exhook.v2.ClientConnackRequest
+	6,  // 59: emqx.exhook.v2.HookProvider.OnClientConnected:input_type -> emqx.exhook.v2.ClientConnectedRequest
+	7,  // 60: emqx.exhook.v2.HookProvider.OnClientDisconnected:input_type -> emqx.exhook.v2.ClientDisconnectedRequest
+	8,  // 61: emqx.exhook.v2.HookProvider.OnClientAuthenticate:input_type -> emqx.exhook.v2.ClientAuthenticateRequest
+	9,  // 62: emqx.exhook.v2.HookProvider.OnClientAuthorize:input_type -> emqx.exhook.v2.ClientAuthorizeRequest
+	10, // 63: emqx.exhook.v2.HookProvider.OnClientSubscribe:input_type -> emqx.exhook.v2.ClientSubscribeRequest
+	11, // 64: emqx.exhook.v2.HookProvider.OnClientUnsubscribe:input_type -> emqx.exhook.v2.ClientUnsubscribeRequest
+	12, // 65: emqx.exhook.v2.HookProvider.OnSessionCreated:input_type -> emqx.exhook.v2.SessionCreatedRequest
+	13, // 66: emqx.exhook.v2.HookProvider.OnSessionSubscribed:input_type -> emqx.exhook.v2.SessionSubscribedRequest
+	14, // 67: emqx.exhook.v2.HookProvider.OnSessionUnsubscribed:input_type -> emqx.exhook.v2.SessionUnsubscribedRequest
+	15, // 68: emqx.exhook.v2.HookProvider.OnSessionResumed:input_type -> emqx.exhook.v2.SessionResumedRequest
+	16, // 69: emqx.exhook.v2.HookProvider.OnSessionDiscarded:input_type -> emqx.exhook.v2.SessionDiscardedRequest
+	17, // 70: emqx.exhook.v2.HookProvider.OnSessionTakenover:input_type -> emqx.exhook.v2.SessionTakenoverRequest
+	18, // 71: emqx.exhook.v2.HookProvider.OnSessionTerminated:input_type -> emqx.exhook.v2.SessionTerminatedRequest
+	19, // 72: emqx.exhook.v2.HookProvider.OnMessagePublish:input_type -> emqx.exhook.v2.MessagePublishRequest
+	20, // 73: emqx.exhook.v2.HookProvider.OnMessageDelivered:input_type -> emqx.exhook.v2.MessageDeliveredRequest
+	21, // 74: emqx.exhook.v2.HookProvider.OnMessageDropped:input_type -> emqx.exhook.v2.MessageDroppedRequest
+	22, // 75: emqx.exhook.v2.HookProvider.OnMessageAcked:input_type -> emqx.exhook.v2.MessageAckedRequest
+	23, // 76: emqx.exhook.v2.HookProvider.OnProviderLoaded:output_type -> emqx.exhook.v2.LoadedResponse
+	25, // 77: emqx.exhook.v2.HookProvider.OnProviderUnloaded:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 78: emqx.exhook.v2.HookProvider.OnClientConnect:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 79: emqx.exhook.v2.HookProvider.OnClientConnack:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 80: emqx.exhook.v2.HookProvider.OnClientConnected:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 81: emqx.exhook.v2.HookProvider.OnClientDisconnected:output_type -> emqx.exhook.v2.EmptySuccess
+	24, // 82: emqx.exhook.v2.HookProvider.OnClientAuthenticate:output_type -> emqx.exhook.v2.ValuedResponse
+	24, // 83: emqx.exhook.v2.HookProvider.OnClientAuthorize:output_type -> emqx.exhook.v2.ValuedResponse
+	25, // 84: emqx.exhook.v2.HookProvider.OnClientSubscribe:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 85: emqx.exhook.v2.HookProvider.OnClientUnsubscribe:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 86: emqx.exhook.v2.HookProvider.OnSessionCreated:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 87: emqx.exhook.v2.HookProvider.OnSessionSubscribed:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 88: emqx.exhook.v2.HookProvider.OnSessionUnsubscribed:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 89: emqx.exhook.v2.HookProvider.OnSessionResumed:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 90: emqx.exhook.v2.HookProvider.OnSessionDiscarded:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 91: emqx.exhook.v2.HookProvider.OnSessionTakenover:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 92: emqx.exhook.v2.HookProvider.OnSessionTerminated:output_type -> emqx.exhook.v2.EmptySuccess
+	24, // 93: emqx.exhook.v2.HookProvider.OnMessagePublish:output_type -> emqx.exhook.v2.ValuedResponse
+	25, // 94: emqx.exhook.v2.HookProvider.OnMessageDelivered:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 95: emqx.exhook.v2.HookProvider.OnMessageDropped:output_type -> emqx.exhook.v2.EmptySuccess
+	25, // 96: emqx.exhook.v2.HookProvider.OnMessageAcked:output_type -> emqx.exhook.v2.EmptySuccess
+	76, // [76:97] is the sub-list for method output_type
+	55, // [55:76] is the sub-list for method input_type
+	55, // [55:55] is the sub-list for extension type_name
+	55, // [55:55] is the sub-list for extension extendee
+	0,  // [0:55] is the sub-list for field type_name
+}
+
+func init() { file_protobuf_exhook_proto_init() }
+func file_protobuf_exhook_proto_init() {
+	if File_protobuf_exhook_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_protobuf_exhook_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ProviderLoadedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ProviderUnloadedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientConnectRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientConnackRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientConnectedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientDisconnectedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientAuthenticateRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientAuthorizeRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientSubscribeRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientUnsubscribeRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionCreatedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionSubscribedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionUnsubscribedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionResumedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionDiscardedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionTakenoverRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SessionTerminatedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MessagePublishRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MessageDeliveredRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MessageDroppedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MessageAckedRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*LoadedResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ValuedResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*EmptySuccess); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*BrokerInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*HookSpec); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ConnInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Message); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Property); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TopicFilter); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SubOpts); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_protobuf_exhook_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*RequestMeta); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	file_protobuf_exhook_proto_msgTypes[22].OneofWrappers = []interface{}{
+		(*ValuedResponse_BoolResult)(nil),
+		(*ValuedResponse_Message)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_protobuf_exhook_proto_rawDesc,
+			NumEnums:      2,
+			NumMessages:   34,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_protobuf_exhook_proto_goTypes,
+		DependencyIndexes: file_protobuf_exhook_proto_depIdxs,
+		EnumInfos:         file_protobuf_exhook_proto_enumTypes,
+		MessageInfos:      file_protobuf_exhook_proto_msgTypes,
+	}.Build()
+	File_protobuf_exhook_proto = out.File
+	file_protobuf_exhook_proto_rawDesc = nil
+	file_protobuf_exhook_proto_goTypes = nil
+	file_protobuf_exhook_proto_depIdxs = nil
+}

+ 499 - 0
services/emqx-agent/protobuf/exhook.proto

@@ -0,0 +1,499 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+syntax = "proto3";
+
+option csharp_namespace = "Emqx.Exhook.V2";
+option go_package = "emqx.io/grpc/exhook";
+option java_multiple_files = true;
+option java_package = "io.emqx.exhook";
+option java_outer_classname = "EmqxExHookProto";
+
+// The exhook proto version should be fixed as `v2` in EMQX v5.x
+// to make sure the exhook proto version is compatible
+package emqx.exhook.v2;
+
+service HookProvider {
+
+  rpc OnProviderLoaded(ProviderLoadedRequest) returns (LoadedResponse) {};
+
+  rpc OnProviderUnloaded(ProviderUnloadedRequest) returns (EmptySuccess) {};
+
+  rpc OnClientConnect(ClientConnectRequest) returns (EmptySuccess) {};
+
+  rpc OnClientConnack(ClientConnackRequest) returns (EmptySuccess) {};
+
+  rpc OnClientConnected(ClientConnectedRequest) returns (EmptySuccess) {};
+
+  rpc OnClientDisconnected(ClientDisconnectedRequest) returns (EmptySuccess) {};
+
+  rpc OnClientAuthenticate(ClientAuthenticateRequest) returns (ValuedResponse) {};
+
+  rpc OnClientAuthorize(ClientAuthorizeRequest) returns (ValuedResponse) {};
+
+  rpc OnClientSubscribe(ClientSubscribeRequest) returns (EmptySuccess) {};
+
+  rpc OnClientUnsubscribe(ClientUnsubscribeRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionCreated(SessionCreatedRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionSubscribed(SessionSubscribedRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionUnsubscribed(SessionUnsubscribedRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionResumed(SessionResumedRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionDiscarded(SessionDiscardedRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionTakenover(SessionTakenoverRequest) returns (EmptySuccess) {};
+
+  rpc OnSessionTerminated(SessionTerminatedRequest) returns (EmptySuccess) {};
+
+  rpc OnMessagePublish(MessagePublishRequest) returns (ValuedResponse) {};
+
+  rpc OnMessageDelivered(MessageDeliveredRequest) returns (EmptySuccess) {};
+
+  rpc OnMessageDropped(MessageDroppedRequest) returns (EmptySuccess) {};
+
+  rpc OnMessageAcked(MessageAckedRequest) returns (EmptySuccess) {};
+}
+
+//------------------------------------------------------------------------------
+// Request
+//------------------------------------------------------------------------------
+
+message ProviderLoadedRequest {
+
+  BrokerInfo broker = 1;
+
+  RequestMeta meta = 2;
+}
+
+message ProviderUnloadedRequest {
+
+  RequestMeta meta = 1;
+}
+
+message ClientConnectRequest {
+
+  ConnInfo conninfo = 1;
+
+  // MQTT CONNECT packet's properties (MQTT v5.0)
+  //
+  // It should be empty on MQTT v3.1.1/v3.1 or others protocol
+  repeated Property props = 2;
+
+  RequestMeta meta = 3;
+}
+
+message ClientConnackRequest {
+
+  ConnInfo conninfo = 1;
+
+  string result_code = 2;
+
+  repeated Property props = 3;
+
+  RequestMeta meta = 4;
+}
+
+message ClientConnectedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  RequestMeta meta = 2;
+}
+
+message ClientDisconnectedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  string reason = 2;
+
+  RequestMeta meta = 3;
+}
+
+message ClientAuthenticateRequest {
+
+  ClientInfo clientinfo = 1;
+
+  bool result = 2;
+
+  RequestMeta meta = 3;
+}
+
+message ClientAuthorizeRequest {
+
+  ClientInfo clientinfo = 1;
+
+  enum AuthorizeReqType {
+
+    PUBLISH = 0;
+
+    SUBSCRIBE = 1;
+  }
+
+  AuthorizeReqType type = 2;
+
+  string topic = 3;
+
+  bool result = 4;
+
+  RequestMeta meta = 5;
+}
+
+message ClientSubscribeRequest {
+
+  ClientInfo clientinfo = 1;
+
+  repeated Property props = 2;
+
+  repeated TopicFilter topic_filters = 3;
+
+  RequestMeta meta = 4;
+}
+
+message ClientUnsubscribeRequest {
+
+  ClientInfo clientinfo = 1;
+
+  repeated Property props = 2;
+
+  repeated TopicFilter topic_filters = 3;
+
+  RequestMeta meta = 4;
+}
+
+message SessionCreatedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  RequestMeta meta = 2;
+}
+
+message SessionSubscribedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  string topic = 2;
+
+  SubOpts subopts = 3;
+
+  RequestMeta meta = 4;
+}
+
+message SessionUnsubscribedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  string topic = 2;
+
+  RequestMeta meta = 3;
+}
+
+message SessionResumedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  RequestMeta meta = 2;
+}
+
+message SessionDiscardedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  RequestMeta meta = 2;
+}
+
+message SessionTakenoverRequest {
+
+  ClientInfo clientinfo = 1;
+
+  RequestMeta meta = 2;
+}
+
+message SessionTerminatedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  string reason = 2;
+
+  RequestMeta meta = 3;
+}
+
+message MessagePublishRequest {
+
+  Message message = 1;
+
+  RequestMeta meta = 2;
+}
+
+message MessageDeliveredRequest {
+
+  ClientInfo clientinfo = 1;
+
+  Message message = 2;
+
+  RequestMeta meta = 3;
+}
+
+message MessageDroppedRequest {
+
+  Message message = 1;
+
+  string reason = 2;
+
+  RequestMeta meta = 3;
+}
+
+message MessageAckedRequest {
+
+  ClientInfo clientinfo = 1;
+
+  Message message = 2;
+
+  RequestMeta meta = 3;
+}
+
+//------------------------------------------------------------------------------
+// Response
+//------------------------------------------------------------------------------
+
+// Responsed by `ProviderLoadedRequest`
+
+message LoadedResponse {
+
+  repeated HookSpec hooks = 1;
+}
+
+// Responsed by `ClientAuthenticateRequest` `ClientAuthorizeRequest` `MessagePublishRequest`
+
+message ValuedResponse {
+
+  // The responded value type
+  //  - contiune: Use the responded value and execute the next hook
+  //  - ignore: Ignore the responded value
+  //  - stop_and_return: Use the responded value and stop the chain executing
+  enum ResponsedType {
+
+    CONTINUE = 0;
+
+    IGNORE = 1;
+
+    STOP_AND_RETURN = 2;
+  }
+
+  ResponsedType type = 1;
+
+  oneof value {
+
+    // Boolean result, used on the 'client.authenticate', 'client.authorize' hooks
+    bool bool_result = 3;
+
+    // Message result, used on the 'message.*' hooks
+    Message message = 4;
+  }
+}
+
+// no Response by other Requests
+
+message EmptySuccess {}
+
+//------------------------------------------------------------------------------
+// Basic data types
+//------------------------------------------------------------------------------
+
+message BrokerInfo {
+
+  string version = 1;
+
+  string sysdescr = 2;
+
+  int64 uptime = 3;
+
+  string datetime = 4;
+}
+
+
+message HookSpec {
+
+  // The registered hooks name
+  //
+  // Available value:
+  //   "client.connect",      "client.connack"
+  //   "client.connected",    "client.disconnected"
+  //   "client.authenticate", "client.authorize"
+  //   "client.subscribe",    "client.unsubscribe"
+  //
+  //   "session.created",      "session.subscribed"
+  //   "session.unsubscribed", "session.resumed"
+  //   "session.discarded",    "session.takenover"
+  //   "session.terminated"
+  //
+  //   "message.publish", "message.delivered"
+  //   "message.acked",   "message.dropped"
+  string name = 1;
+
+  // The topic filters for message hooks
+  repeated string topics = 2;
+}
+
+message ConnInfo {
+
+  string node = 1;
+
+  string clientid = 2;
+
+  string username = 3;
+
+  string peerhost = 4;
+
+  uint32 sockport = 5;
+
+  string proto_name = 6;
+
+  string proto_ver = 7;
+
+  uint32 keepalive = 8;
+}
+
+message ClientInfo {
+
+  string node = 1;
+
+  string clientid = 2;
+
+  string username = 3;
+
+  string password = 4;
+
+  string peerhost = 5;
+
+  uint32 sockport = 6;
+
+  string protocol = 7;
+
+  string mountpoint = 8;
+
+  bool  is_superuser = 9;
+
+  bool  anonymous = 10;
+
+  // common name of client TLS cert
+  string cn = 11;
+
+  // subject of client TLS cert
+  string dn = 12;
+}
+
+message Message {
+
+  string node = 1;
+
+  string id = 2;
+
+  uint32 qos = 3;
+
+  string from = 4;
+
+  string topic = 5;
+
+  bytes  payload = 6;
+
+  uint64 timestamp = 7;
+
+  // The key of header can be:
+  //  - username:
+  //    * Readonly
+  //    * The username of sender client
+  //    * Value type: utf8 string
+  //  - protocol:
+  //    * Readonly
+  //    * The protocol name of sender client
+  //    * Value type: string enum with "mqtt", "mqtt-sn", ...
+  //  - peerhost:
+  //    * Readonly
+  //    * The peerhost of sender client
+  //    * Value type: ip address string
+  //  - allow_publish:
+  //    * Writable
+  //    * Whether to allow the message to be published by emqx
+  //    * Value type: string enum with "true", "false", default is "true"
+  //
+  // Notes: All header may be missing, which means that the message does not
+  //   carry these headers. We can guarantee that clients coming from MQTT,
+  //   MQTT-SN, CoAP, LwM2M and other natively supported protocol clients will
+  //   carry these headers, but there is no guarantee that messages published
+  //   by other means will do, e.g. messages published by HTTP-API
+  map<string, string> headers = 8;
+}
+
+message Property {
+
+  string name = 1;
+
+  string value = 2;
+}
+
+message TopicFilter {
+
+  string name = 1;
+
+  uint32 qos = 2;
+}
+
+message SubOpts {
+
+  // The QoS level
+  uint32 qos = 1;
+
+  // The group name for shared subscription
+  string share = 2;
+
+  // The Retain Handling option (MQTT v5.0)
+  //
+  //  0 = Send retained messages at the time of the subscribe
+  //  1 = Send retained messages at subscribe only if the subscription does
+  //       not currently exist
+  //  2 = Do not send retained messages at the time of the subscribe
+  uint32 rh = 3;
+
+  // The Retain as Published option (MQTT v5.0)
+  //
+  //  If 1, Application Messages forwarded using this subscription keep the
+  //        RETAIN flag they were published with.
+  //  If 0, Application Messages forwarded using this subscription have the
+  //        RETAIN flag set to 0.
+  // Retained messages sent when the subscription is established have the RETAIN flag set to 1.
+  uint32 rap = 4;
+
+  // The No Local option (MQTT v5.0)
+  //
+  // If the value is 1, Application Messages MUST NOT be forwarded to a
+  // connection with a ClientID equal to the ClientID of the publishing
+  uint32 nl = 5;
+}
+
+message RequestMeta {
+
+  string node = 1;
+
+  string version = 2;
+
+  string sysdescr = 3;
+
+  string cluster_name = 4;
+}

+ 868 - 0
services/emqx-agent/protobuf/exhook_grpc.pb.go

@@ -0,0 +1,868 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.3.0
+// - protoc             v4.25.1
+// source: protobuf/exhook.proto
+
+// The exhook proto version should be fixed as `v2` in EMQX v5.x
+// to make sure the exhook proto version is compatible
+
+package exhook
+
+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
+
+const (
+	HookProvider_OnProviderLoaded_FullMethodName      = "/emqx.exhook.v2.HookProvider/OnProviderLoaded"
+	HookProvider_OnProviderUnloaded_FullMethodName    = "/emqx.exhook.v2.HookProvider/OnProviderUnloaded"
+	HookProvider_OnClientConnect_FullMethodName       = "/emqx.exhook.v2.HookProvider/OnClientConnect"
+	HookProvider_OnClientConnack_FullMethodName       = "/emqx.exhook.v2.HookProvider/OnClientConnack"
+	HookProvider_OnClientConnected_FullMethodName     = "/emqx.exhook.v2.HookProvider/OnClientConnected"
+	HookProvider_OnClientDisconnected_FullMethodName  = "/emqx.exhook.v2.HookProvider/OnClientDisconnected"
+	HookProvider_OnClientAuthenticate_FullMethodName  = "/emqx.exhook.v2.HookProvider/OnClientAuthenticate"
+	HookProvider_OnClientAuthorize_FullMethodName     = "/emqx.exhook.v2.HookProvider/OnClientAuthorize"
+	HookProvider_OnClientSubscribe_FullMethodName     = "/emqx.exhook.v2.HookProvider/OnClientSubscribe"
+	HookProvider_OnClientUnsubscribe_FullMethodName   = "/emqx.exhook.v2.HookProvider/OnClientUnsubscribe"
+	HookProvider_OnSessionCreated_FullMethodName      = "/emqx.exhook.v2.HookProvider/OnSessionCreated"
+	HookProvider_OnSessionSubscribed_FullMethodName   = "/emqx.exhook.v2.HookProvider/OnSessionSubscribed"
+	HookProvider_OnSessionUnsubscribed_FullMethodName = "/emqx.exhook.v2.HookProvider/OnSessionUnsubscribed"
+	HookProvider_OnSessionResumed_FullMethodName      = "/emqx.exhook.v2.HookProvider/OnSessionResumed"
+	HookProvider_OnSessionDiscarded_FullMethodName    = "/emqx.exhook.v2.HookProvider/OnSessionDiscarded"
+	HookProvider_OnSessionTakenover_FullMethodName    = "/emqx.exhook.v2.HookProvider/OnSessionTakenover"
+	HookProvider_OnSessionTerminated_FullMethodName   = "/emqx.exhook.v2.HookProvider/OnSessionTerminated"
+	HookProvider_OnMessagePublish_FullMethodName      = "/emqx.exhook.v2.HookProvider/OnMessagePublish"
+	HookProvider_OnMessageDelivered_FullMethodName    = "/emqx.exhook.v2.HookProvider/OnMessageDelivered"
+	HookProvider_OnMessageDropped_FullMethodName      = "/emqx.exhook.v2.HookProvider/OnMessageDropped"
+	HookProvider_OnMessageAcked_FullMethodName        = "/emqx.exhook.v2.HookProvider/OnMessageAcked"
+)
+
+// HookProviderClient is the client API for HookProvider 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 HookProviderClient interface {
+	OnProviderLoaded(ctx context.Context, in *ProviderLoadedRequest, opts ...grpc.CallOption) (*LoadedResponse, error)
+	OnProviderUnloaded(ctx context.Context, in *ProviderUnloadedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnClientConnect(ctx context.Context, in *ClientConnectRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnClientConnack(ctx context.Context, in *ClientConnackRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnClientConnected(ctx context.Context, in *ClientConnectedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnClientDisconnected(ctx context.Context, in *ClientDisconnectedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnClientAuthenticate(ctx context.Context, in *ClientAuthenticateRequest, opts ...grpc.CallOption) (*ValuedResponse, error)
+	OnClientAuthorize(ctx context.Context, in *ClientAuthorizeRequest, opts ...grpc.CallOption) (*ValuedResponse, error)
+	OnClientSubscribe(ctx context.Context, in *ClientSubscribeRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnClientUnsubscribe(ctx context.Context, in *ClientUnsubscribeRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionCreated(ctx context.Context, in *SessionCreatedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionSubscribed(ctx context.Context, in *SessionSubscribedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionUnsubscribed(ctx context.Context, in *SessionUnsubscribedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionResumed(ctx context.Context, in *SessionResumedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionDiscarded(ctx context.Context, in *SessionDiscardedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionTakenover(ctx context.Context, in *SessionTakenoverRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnSessionTerminated(ctx context.Context, in *SessionTerminatedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnMessagePublish(ctx context.Context, in *MessagePublishRequest, opts ...grpc.CallOption) (*ValuedResponse, error)
+	OnMessageDelivered(ctx context.Context, in *MessageDeliveredRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnMessageDropped(ctx context.Context, in *MessageDroppedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+	OnMessageAcked(ctx context.Context, in *MessageAckedRequest, opts ...grpc.CallOption) (*EmptySuccess, error)
+}
+
+type hookProviderClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewHookProviderClient(cc grpc.ClientConnInterface) HookProviderClient {
+	return &hookProviderClient{cc}
+}
+
+func (c *hookProviderClient) OnProviderLoaded(ctx context.Context, in *ProviderLoadedRequest, opts ...grpc.CallOption) (*LoadedResponse, error) {
+	out := new(LoadedResponse)
+	err := c.cc.Invoke(ctx, HookProvider_OnProviderLoaded_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnProviderUnloaded(ctx context.Context, in *ProviderUnloadedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnProviderUnloaded_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientConnect(ctx context.Context, in *ClientConnectRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientConnect_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientConnack(ctx context.Context, in *ClientConnackRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientConnack_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientConnected(ctx context.Context, in *ClientConnectedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientConnected_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientDisconnected(ctx context.Context, in *ClientDisconnectedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientDisconnected_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientAuthenticate(ctx context.Context, in *ClientAuthenticateRequest, opts ...grpc.CallOption) (*ValuedResponse, error) {
+	out := new(ValuedResponse)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientAuthenticate_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientAuthorize(ctx context.Context, in *ClientAuthorizeRequest, opts ...grpc.CallOption) (*ValuedResponse, error) {
+	out := new(ValuedResponse)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientAuthorize_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientSubscribe(ctx context.Context, in *ClientSubscribeRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientSubscribe_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnClientUnsubscribe(ctx context.Context, in *ClientUnsubscribeRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnClientUnsubscribe_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionCreated(ctx context.Context, in *SessionCreatedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionCreated_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionSubscribed(ctx context.Context, in *SessionSubscribedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionSubscribed_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionUnsubscribed(ctx context.Context, in *SessionUnsubscribedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionUnsubscribed_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionResumed(ctx context.Context, in *SessionResumedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionResumed_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionDiscarded(ctx context.Context, in *SessionDiscardedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionDiscarded_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionTakenover(ctx context.Context, in *SessionTakenoverRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionTakenover_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnSessionTerminated(ctx context.Context, in *SessionTerminatedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnSessionTerminated_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnMessagePublish(ctx context.Context, in *MessagePublishRequest, opts ...grpc.CallOption) (*ValuedResponse, error) {
+	out := new(ValuedResponse)
+	err := c.cc.Invoke(ctx, HookProvider_OnMessagePublish_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnMessageDelivered(ctx context.Context, in *MessageDeliveredRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnMessageDelivered_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnMessageDropped(ctx context.Context, in *MessageDroppedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnMessageDropped_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *hookProviderClient) OnMessageAcked(ctx context.Context, in *MessageAckedRequest, opts ...grpc.CallOption) (*EmptySuccess, error) {
+	out := new(EmptySuccess)
+	err := c.cc.Invoke(ctx, HookProvider_OnMessageAcked_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// HookProviderServer is the server API for HookProvider service.
+// All implementations must embed UnimplementedHookProviderServer
+// for forward compatibility
+type HookProviderServer interface {
+	OnProviderLoaded(context.Context, *ProviderLoadedRequest) (*LoadedResponse, error)
+	OnProviderUnloaded(context.Context, *ProviderUnloadedRequest) (*EmptySuccess, error)
+	OnClientConnect(context.Context, *ClientConnectRequest) (*EmptySuccess, error)
+	OnClientConnack(context.Context, *ClientConnackRequest) (*EmptySuccess, error)
+	OnClientConnected(context.Context, *ClientConnectedRequest) (*EmptySuccess, error)
+	OnClientDisconnected(context.Context, *ClientDisconnectedRequest) (*EmptySuccess, error)
+	OnClientAuthenticate(context.Context, *ClientAuthenticateRequest) (*ValuedResponse, error)
+	OnClientAuthorize(context.Context, *ClientAuthorizeRequest) (*ValuedResponse, error)
+	OnClientSubscribe(context.Context, *ClientSubscribeRequest) (*EmptySuccess, error)
+	OnClientUnsubscribe(context.Context, *ClientUnsubscribeRequest) (*EmptySuccess, error)
+	OnSessionCreated(context.Context, *SessionCreatedRequest) (*EmptySuccess, error)
+	OnSessionSubscribed(context.Context, *SessionSubscribedRequest) (*EmptySuccess, error)
+	OnSessionUnsubscribed(context.Context, *SessionUnsubscribedRequest) (*EmptySuccess, error)
+	OnSessionResumed(context.Context, *SessionResumedRequest) (*EmptySuccess, error)
+	OnSessionDiscarded(context.Context, *SessionDiscardedRequest) (*EmptySuccess, error)
+	OnSessionTakenover(context.Context, *SessionTakenoverRequest) (*EmptySuccess, error)
+	OnSessionTerminated(context.Context, *SessionTerminatedRequest) (*EmptySuccess, error)
+	OnMessagePublish(context.Context, *MessagePublishRequest) (*ValuedResponse, error)
+	OnMessageDelivered(context.Context, *MessageDeliveredRequest) (*EmptySuccess, error)
+	OnMessageDropped(context.Context, *MessageDroppedRequest) (*EmptySuccess, error)
+	OnMessageAcked(context.Context, *MessageAckedRequest) (*EmptySuccess, error)
+	mustEmbedUnimplementedHookProviderServer()
+}
+
+// UnimplementedHookProviderServer must be embedded to have forward compatible implementations.
+type UnimplementedHookProviderServer struct {
+}
+
+func (UnimplementedHookProviderServer) OnProviderLoaded(context.Context, *ProviderLoadedRequest) (*LoadedResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnProviderLoaded not implemented")
+}
+func (UnimplementedHookProviderServer) OnProviderUnloaded(context.Context, *ProviderUnloadedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnProviderUnloaded not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientConnect(context.Context, *ClientConnectRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientConnect not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientConnack(context.Context, *ClientConnackRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientConnack not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientConnected(context.Context, *ClientConnectedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientConnected not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientDisconnected(context.Context, *ClientDisconnectedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientDisconnected not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientAuthenticate(context.Context, *ClientAuthenticateRequest) (*ValuedResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientAuthenticate not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientAuthorize(context.Context, *ClientAuthorizeRequest) (*ValuedResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientAuthorize not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientSubscribe(context.Context, *ClientSubscribeRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientSubscribe not implemented")
+}
+func (UnimplementedHookProviderServer) OnClientUnsubscribe(context.Context, *ClientUnsubscribeRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnClientUnsubscribe not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionCreated(context.Context, *SessionCreatedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionCreated not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionSubscribed(context.Context, *SessionSubscribedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionSubscribed not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionUnsubscribed(context.Context, *SessionUnsubscribedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionUnsubscribed not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionResumed(context.Context, *SessionResumedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionResumed not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionDiscarded(context.Context, *SessionDiscardedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionDiscarded not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionTakenover(context.Context, *SessionTakenoverRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionTakenover not implemented")
+}
+func (UnimplementedHookProviderServer) OnSessionTerminated(context.Context, *SessionTerminatedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnSessionTerminated not implemented")
+}
+func (UnimplementedHookProviderServer) OnMessagePublish(context.Context, *MessagePublishRequest) (*ValuedResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnMessagePublish not implemented")
+}
+func (UnimplementedHookProviderServer) OnMessageDelivered(context.Context, *MessageDeliveredRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnMessageDelivered not implemented")
+}
+func (UnimplementedHookProviderServer) OnMessageDropped(context.Context, *MessageDroppedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnMessageDropped not implemented")
+}
+func (UnimplementedHookProviderServer) OnMessageAcked(context.Context, *MessageAckedRequest) (*EmptySuccess, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method OnMessageAcked not implemented")
+}
+func (UnimplementedHookProviderServer) mustEmbedUnimplementedHookProviderServer() {}
+
+// UnsafeHookProviderServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to HookProviderServer will
+// result in compilation errors.
+type UnsafeHookProviderServer interface {
+	mustEmbedUnimplementedHookProviderServer()
+}
+
+func RegisterHookProviderServer(s grpc.ServiceRegistrar, srv HookProviderServer) {
+	s.RegisterService(&HookProvider_ServiceDesc, srv)
+}
+
+func _HookProvider_OnProviderLoaded_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ProviderLoadedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnProviderLoaded(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnProviderLoaded_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnProviderLoaded(ctx, req.(*ProviderLoadedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnProviderUnloaded_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ProviderUnloadedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnProviderUnloaded(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnProviderUnloaded_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnProviderUnloaded(ctx, req.(*ProviderUnloadedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientConnect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientConnectRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientConnect(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientConnect_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientConnect(ctx, req.(*ClientConnectRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientConnack_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientConnackRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientConnack(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientConnack_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientConnack(ctx, req.(*ClientConnackRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientConnected_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientConnectedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientConnected(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientConnected_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientConnected(ctx, req.(*ClientConnectedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientDisconnected_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientDisconnectedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientDisconnected(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientDisconnected_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientDisconnected(ctx, req.(*ClientDisconnectedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientAuthenticate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientAuthenticateRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientAuthenticate(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientAuthenticate_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientAuthenticate(ctx, req.(*ClientAuthenticateRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientAuthorize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientAuthorizeRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientAuthorize(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientAuthorize_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientAuthorize(ctx, req.(*ClientAuthorizeRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientSubscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientSubscribeRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientSubscribe(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientSubscribe_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientSubscribe(ctx, req.(*ClientSubscribeRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnClientUnsubscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ClientUnsubscribeRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnClientUnsubscribe(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnClientUnsubscribe_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnClientUnsubscribe(ctx, req.(*ClientUnsubscribeRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionCreated_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionCreatedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionCreated(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionCreated_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionCreated(ctx, req.(*SessionCreatedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionSubscribed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionSubscribedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionSubscribed(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionSubscribed_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionSubscribed(ctx, req.(*SessionSubscribedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionUnsubscribed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionUnsubscribedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionUnsubscribed(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionUnsubscribed_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionUnsubscribed(ctx, req.(*SessionUnsubscribedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionResumed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionResumedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionResumed(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionResumed_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionResumed(ctx, req.(*SessionResumedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionDiscarded_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionDiscardedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionDiscarded(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionDiscarded_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionDiscarded(ctx, req.(*SessionDiscardedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionTakenover_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionTakenoverRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionTakenover(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionTakenover_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionTakenover(ctx, req.(*SessionTakenoverRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnSessionTerminated_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SessionTerminatedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnSessionTerminated(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnSessionTerminated_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnSessionTerminated(ctx, req.(*SessionTerminatedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnMessagePublish_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(MessagePublishRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnMessagePublish(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnMessagePublish_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnMessagePublish(ctx, req.(*MessagePublishRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnMessageDelivered_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(MessageDeliveredRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnMessageDelivered(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnMessageDelivered_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnMessageDelivered(ctx, req.(*MessageDeliveredRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnMessageDropped_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(MessageDroppedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnMessageDropped(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnMessageDropped_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnMessageDropped(ctx, req.(*MessageDroppedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _HookProvider_OnMessageAcked_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(MessageAckedRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HookProviderServer).OnMessageAcked(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: HookProvider_OnMessageAcked_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HookProviderServer).OnMessageAcked(ctx, req.(*MessageAckedRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// HookProvider_ServiceDesc is the grpc.ServiceDesc for HookProvider service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var HookProvider_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "emqx.exhook.v2.HookProvider",
+	HandlerType: (*HookProviderServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "OnProviderLoaded",
+			Handler:    _HookProvider_OnProviderLoaded_Handler,
+		},
+		{
+			MethodName: "OnProviderUnloaded",
+			Handler:    _HookProvider_OnProviderUnloaded_Handler,
+		},
+		{
+			MethodName: "OnClientConnect",
+			Handler:    _HookProvider_OnClientConnect_Handler,
+		},
+		{
+			MethodName: "OnClientConnack",
+			Handler:    _HookProvider_OnClientConnack_Handler,
+		},
+		{
+			MethodName: "OnClientConnected",
+			Handler:    _HookProvider_OnClientConnected_Handler,
+		},
+		{
+			MethodName: "OnClientDisconnected",
+			Handler:    _HookProvider_OnClientDisconnected_Handler,
+		},
+		{
+			MethodName: "OnClientAuthenticate",
+			Handler:    _HookProvider_OnClientAuthenticate_Handler,
+		},
+		{
+			MethodName: "OnClientAuthorize",
+			Handler:    _HookProvider_OnClientAuthorize_Handler,
+		},
+		{
+			MethodName: "OnClientSubscribe",
+			Handler:    _HookProvider_OnClientSubscribe_Handler,
+		},
+		{
+			MethodName: "OnClientUnsubscribe",
+			Handler:    _HookProvider_OnClientUnsubscribe_Handler,
+		},
+		{
+			MethodName: "OnSessionCreated",
+			Handler:    _HookProvider_OnSessionCreated_Handler,
+		},
+		{
+			MethodName: "OnSessionSubscribed",
+			Handler:    _HookProvider_OnSessionSubscribed_Handler,
+		},
+		{
+			MethodName: "OnSessionUnsubscribed",
+			Handler:    _HookProvider_OnSessionUnsubscribed_Handler,
+		},
+		{
+			MethodName: "OnSessionResumed",
+			Handler:    _HookProvider_OnSessionResumed_Handler,
+		},
+		{
+			MethodName: "OnSessionDiscarded",
+			Handler:    _HookProvider_OnSessionDiscarded_Handler,
+		},
+		{
+			MethodName: "OnSessionTakenover",
+			Handler:    _HookProvider_OnSessionTakenover_Handler,
+		},
+		{
+			MethodName: "OnSessionTerminated",
+			Handler:    _HookProvider_OnSessionTerminated_Handler,
+		},
+		{
+			MethodName: "OnMessagePublish",
+			Handler:    _HookProvider_OnMessagePublish_Handler,
+		},
+		{
+			MethodName: "OnMessageDelivered",
+			Handler:    _HookProvider_OnMessageDelivered_Handler,
+		},
+		{
+			MethodName: "OnMessageDropped",
+			Handler:    _HookProvider_OnMessageDropped_Handler,
+		},
+		{
+			MethodName: "OnMessageAcked",
+			Handler:    _HookProvider_OnMessageAcked_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "protobuf/exhook.proto",
+}

+ 10 - 0
services/emqx-agent/readme.md

@@ -0,0 +1,10 @@
+## emqx 代理服务
+
+主要作为 emqx 服务的代理,实现emqx hook服务,监听设备接入的事件,维护设备上下线状态,服务启动后订阅所有设备消息并作预处理,转发到规则引擎中。
+
+### 核心功能
+
+* EMQX服务 ExHook 服务,实现了 GPRC
+* 根据hook 事件,完成设备上下线状态维护
+* 订阅设备消息并转发到规则引擎中
+* 实现 easeLink 协议,适配 api provider 服务中的请求,生成协议包转发到设备相应的主题上。

+ 204 - 0
services/emqx-agent/sub_dev.go

@@ -0,0 +1,204 @@
+package main
+
+import (
+	"context"
+	"encoding/json"
+	mqtt "github.com/eclipse/paho.mqtt.golang"
+	"github.com/gogf/gf/os/grpool"
+	"runtime"
+	"runtime/debug"
+	"sparrow/pkg/protocol"
+	"sparrow/pkg/server"
+	"sparrow/services/emqx-agent/client"
+	"strings"
+	"time"
+)
+
+type SubDev interface {
+	SubDevMsg(handle Handle) error
+	PublishToMsgToDev(topic string, payload []byte) error
+}
+
+type ConnectMsg struct {
+	Username       string `json:"username"`
+	Ts             int64  `json:"ts"`
+	Sockport       int    `json:"sockport"`
+	ProtoVer       int    `json:"proto_ver"`
+	ProtoName      string `json:"proto_name"`
+	Keepalive      int    `json:"keepalive"`
+	Ipaddress      string `json:"ipaddress"`
+	ExpiryInterval int    `json:"expiry_interval"`
+	ConnectedAt    int64  `json:"connected_at"`
+	Connack        int    `json:"connack"`
+	Clientid       string `json:"clientid"`
+	Reason         string `json:"reason"`
+	CleanStart     bool   `json:"clean_start"`
+}
+
+type Handle func(ctx context.Context) DevSubHandle
+
+type DevSubHandle interface {
+	Message(topic string, payload []byte) error
+	Connected(status *protocol.DevConnectStatus) error
+	Disconnected(status *protocol.DevConnectStatus) error
+}
+
+type MqttClient struct {
+	client     *client.MqttClient
+	handlePool *grpool.Pool
+}
+
+func (d *MqttClient) PublishToMsgToDev(topic string, payload []byte) error {
+	return d.client.Publish(topic, 1, false, payload)
+}
+
+const (
+	ShareSubTopicPrefix = "$share/sparrow.agent/"
+	TopicConnectStatus  = ShareSubTopicPrefix + "$SYS/brokers/+/clients/#"
+	TopicThing          = ShareSubTopicPrefix + protocol.TopicHeadThing + "/up/#"
+	TopicOta            = ShareSubTopicPrefix + protocol.TopicHeadOta + "/up/#"
+	TopicConfig         = ShareSubTopicPrefix + protocol.TopicHeadConfig + "/up/#"
+	TopicSDKLog         = ShareSubTopicPrefix + protocol.TopicHeadLog + "/up/#"
+	TopicShadow         = ShareSubTopicPrefix + protocol.TopicHeadShadow + "/up/#"
+	TopicGateway        = ShareSubTopicPrefix + protocol.TopicHeadGateway + "/up/#"
+	TopicExt            = ShareSubTopicPrefix + protocol.TopicHeadExt + "/up/#"
+)
+
+func NewSubDev(conf *client.MqttConfig) (SubDev, error) {
+	return newEmqClient(conf)
+}
+
+func newEmqClient(conf *client.MqttConfig) (SubDev, error) {
+	mc, err := client.NewMqttClient(conf)
+	if err != nil {
+		return nil, err
+	}
+	return &MqttClient{
+		client:     mc,
+		handlePool: grpool.New(1000),
+	}, nil
+}
+
+func (d *MqttClient) SubDevMsg(handle Handle) error {
+
+	err := d.subDevMsg(nil, handle)
+	if err != nil {
+		return err
+	}
+	client.SetMqttSetOnConnectHandler(func(cli mqtt.Client) {
+		err := d.subDevMsg(cli, handle)
+		if err != nil {
+			server.Log.Errorf("mqttSetOnConnectHandler.subDevMsg err:%v", err)
+		}
+	})
+	return nil
+}
+
+func (d *MqttClient) subDevMsg(cli mqtt.Client, handle Handle) error {
+	err := d.subscribeWithFunc(cli, TopicConnectStatus, d.subConnectStatus(handle))
+	if err != nil {
+		return err
+	}
+	err = d.subscribeWithFunc(cli, TopicThing, func(ctx context.Context, topic string, payload []byte) error {
+		return handle(ctx).Message(topic, payload)
+	})
+	if err != nil {
+		return err
+	}
+	err = d.subscribeWithFunc(cli, TopicConfig, func(ctx context.Context, topic string, payload []byte) error {
+		return handle(ctx).Message(topic, payload)
+	})
+	if err != nil {
+		return err
+	}
+	err = d.subscribeWithFunc(cli, TopicOta, func(ctx context.Context, topic string, payload []byte) error {
+		return handle(ctx).Message(topic, payload)
+	})
+	if err != nil {
+		return err
+	}
+	err = d.subscribeWithFunc(cli, TopicExt, func(ctx context.Context, topic string, payload []byte) error {
+		return handle(ctx).Message(topic, payload)
+	})
+	if err != nil {
+		return err
+	}
+	err = d.subscribeWithFunc(cli, TopicShadow, func(ctx context.Context, topic string, payload []byte) error {
+		return handle(ctx).Message(topic, payload)
+	})
+
+	if err != nil {
+		return err
+	}
+	err = d.subscribeWithFunc(cli, TopicGateway, func(ctx context.Context, topic string, payload []byte) error {
+		return handle(ctx).Message(topic, payload)
+	})
+	if err != nil {
+		return err
+	}
+	err = d.subscribeWithFunc(cli, TopicSDKLog, func(ctx context.Context, topic string, payload []byte) error {
+		return handle(ctx).Message(topic, payload)
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (d *MqttClient) subConnectStatus(handle Handle) func(ctx context.Context, topic string, payload []byte) error {
+	return func(ctx context.Context, topic string, payload []byte) error {
+		var (
+			msg ConnectMsg
+			err error
+		)
+		err = json.Unmarshal(payload, &msg)
+		if err != nil {
+			server.Log.Errorf("json.Unmarshal err :%s, topic :%v", err, topic)
+			return err
+		}
+		status := protocol.DevConnectStatus{
+			DeviceCode: msg.Username,
+			DeviceId:   msg.Clientid,
+			ClientIp:   msg.Ipaddress,
+		}
+		if strings.HasSuffix(topic, "/connected") || strings.HasSuffix(topic, "/subscribed") {
+			status.Action = "LOGIN"
+			return handle(ctx).Connected(&status)
+		} else {
+			status.Action = "LOGOUT"
+			status.Reason = msg.Reason
+			return handle(ctx).Disconnected(&status)
+		}
+	}
+}
+
+func (d *MqttClient) subscribeWithFunc(cli mqtt.Client, topic string,
+	handle func(ctx context.Context, topic string, payload []byte) error) error {
+	return d.client.Subscribe(cli, topic, 1, func(c mqtt.Client, message mqtt.Message) {
+		_ = d.handlePool.Add(func() {
+			go func() {
+				ctx, cancel := context.WithTimeout(context.Background(), 50*time.Second)
+				defer cancel()
+				Recover(ctx)
+				err := handle(ctx, message.Topic(), message.Payload())
+				if err != nil {
+					server.Log.Errorf("handle failure err :%s, topic :%v", err, topic)
+				}
+			}()
+		})
+	})
+}
+
+func Recover(ctx context.Context) {
+	if p := recover(); p != nil {
+		HandleThrow(ctx, p)
+	}
+}
+
+func HandleThrow(ctx context.Context, p any) {
+	pc := make([]uintptr, 1)
+	runtime.Callers(3, pc)
+	f := runtime.FuncForPC(pc[0])
+	server.Log.Errorf("HandleThrow|func=%s|error=%#v|stack=%s\n", f, p, string(debug.Stack()))
+	//os.Exit(-1)
+}

+ 21 - 0
services/scene-access/README.md

@@ -0,0 +1,21 @@
+## 场景服务
+
+### 核心功能
+
+* 实现场景服务,提供场景管理、场景联动、场景联动规则、场景联动日志, 设备定时服务等功能
+* 将外部提交的任务,根据类型,发布到rabbitMQ中的不同的Queue中,由不同的消费者(任务执行器)进行消费
+
+
+
+### 实现思路
+
+任务类型: 定时类任务,设备上报状态触发类任务,场景联动任务等
+
+使用rabbitmq的exchange的Routing类型,将任务类型作为routing key,将任务内容作为消息体,将消息投递到对应的Queue中
+
+
+### 任务生命周期管理
+
+消息类型:删除,更新,停止,启动。
+
+所有任务的生命周期消息都投递到一个交换机上,交换机的类型为fanout,所有任务执行器都可以订阅该交换机。保证每个执行器都可以管理目前正在执行的任务的生命周期

+ 7 - 0
services/scene-access/internal/service/manager/producer.go

@@ -0,0 +1,7 @@
+package manager
+
+type Producer interface {
+	Init() error
+	Publish(topic string, msg []byte) error
+	CreateTopicIfNotExists(topic string) error
+}

+ 31 - 0
services/scene-access/internal/service/manager/task_lifecycle_manager.go

@@ -0,0 +1,31 @@
+package manager
+
+import (
+	"github.com/streadway/amqp"
+	"sparrow/pkg/rule"
+)
+
+// TaskLifecycleManager 任务生命周期发布管理器
+type TaskLifecycleManager struct {
+	ch *amqp.Channel
+}
+
+func NewTaskLifecycleManager(ch *amqp.Channel) Producer {
+	return &TaskLifecycleManager{ch: ch}
+}
+
+func (t *TaskLifecycleManager) Init() error {
+	return t.ch.ExchangeDeclare(rule.TaskLifecycleExchange, "fanout", true, false, false, false, nil)
+}
+
+func (t *TaskLifecycleManager) Publish(topic string, msg []byte) error {
+	return t.ch.Publish(rule.TaskLifecycleExchange, topic, false, false, amqp.Publishing{
+		Body:         msg,
+		DeliveryMode: amqp.Persistent,
+	})
+}
+
+func (t *TaskLifecycleManager) CreateTopicIfNotExists(topic string) error {
+	//TODO implement me
+	panic("implement me")
+}

+ 38 - 0
services/scene-access/internal/service/manager/task_manager.go

@@ -0,0 +1,38 @@
+package manager
+
+import (
+	"github.com/streadway/amqp"
+	"sparrow/pkg/rule"
+)
+
+// TaskManager 任务发布管理器
+// 发布任务消息到
+type TaskManager struct {
+	ch *amqp.Channel
+}
+
+func NewTaskManager(ch *amqp.Channel) Producer {
+	return &TaskManager{
+		ch: ch,
+	}
+}
+
+func (a *TaskManager) Init() error {
+	// 定义exchange
+	return a.ch.ExchangeDeclare(rule.TaskExchange, "topic", true, false, false, false, nil)
+}
+
+func (a *TaskManager) Publish(topic string, msg []byte) error {
+	err := a.ch.Publish(rule.TaskExchange, topic, false, false, amqp.Publishing{
+		DeliveryMode: amqp.Persistent,
+		Body:         msg,
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (a *TaskManager) CreateTopicIfNotExists(topic string) error {
+	return nil
+}

+ 138 - 0
services/scene-access/internal/service/scene.go

@@ -0,0 +1,138 @@
+package service
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/streadway/amqp"
+	"sparrow/pkg/rpcs"
+	"sparrow/pkg/rule"
+	"sparrow/pkg/server"
+	"sparrow/services/scene-access/internal/service/manager"
+	"time"
+)
+
+const TimerTopic = "sparrow.task.timer" // 定时任务主题
+
+// SceneService 场景服务
+type SceneService struct {
+	rabbitMQAddress    string
+	taskManager        manager.Producer
+	lifecycleManager   manager.Producer
+	done               chan bool
+	isReady            bool
+	conn               *amqp.Connection
+	notifyCloseChannel chan *amqp.Error
+	notifyChanClose    chan *amqp.Error
+	ch                 *amqp.Channel
+}
+
+func NewSceneService(mqAddr string) *SceneService {
+	srv := &SceneService{
+		rabbitMQAddress: mqAddr,
+	}
+	go srv.handleReconnect()
+	return srv
+}
+
+// SubmitTask rpc 提交一个任务
+func (s *SceneService) SubmitTask(args rpcs.ArgsSubmitTask, reply *rpcs.ReplyEmptyResult) error {
+	var (
+		topic string
+	)
+	switch args.Type {
+	case "timer":
+		topic = TimerTopic
+	}
+	return s.taskManager.Publish(topic, []byte(args.Data))
+}
+
+// SubmitTaskLifecycle rpc 提交一个任务生命周期
+func (s *SceneService) SubmitTaskLifecycle(args rpcs.ArgsSubmitTaskLifecycle, reply *rpcs.ReplyEmptyResult) error {
+	taskMsg := rule.TaskLifecycleMessage{
+		TaskId: args.TaskId,
+		Action: args.Action,
+		Data:   args.Data,
+	}
+	data, err := json.Marshal(&taskMsg)
+	if err != nil {
+		return err
+	}
+	return s.lifecycleManager.Publish("sparrow.task.timer.lifecycle", data)
+}
+
+func (s *SceneService) init(conn *amqp.Connection) error {
+	ch, err := conn.Channel()
+	if err != nil {
+		return err
+	}
+	s.ch = ch
+	taskManager := manager.NewTaskManager(ch)
+	err = taskManager.Init()
+	if err != nil {
+		return err
+	}
+	s.taskManager = taskManager
+	lifecycleManager := manager.NewTaskLifecycleManager(ch)
+	err = lifecycleManager.Init()
+	if err != nil {
+		return err
+	}
+	s.lifecycleManager = lifecycleManager
+	s.notifyChanClose = make(chan *amqp.Error)
+	s.ch.NotifyClose(s.notifyChanClose)
+	s.isReady = true
+	return nil
+}
+
+func (s *SceneService) connect() (*amqp.Connection, error) {
+	conn, err := amqp.Dial(s.rabbitMQAddress)
+	if err != nil {
+		return nil, err
+	}
+	s.conn = conn
+	s.notifyCloseChannel = make(chan *amqp.Error)
+	s.conn.NotifyClose(s.notifyCloseChannel)
+	return conn, err
+}
+func (s *SceneService) handleReconnect() {
+	for {
+		s.isReady = false
+		conn, err := s.connect()
+		fmt.Println("handleReconnect")
+		if err != nil {
+			server.Log.Errorf("connect to rabbitmq error:%s", err.Error())
+			select {
+			case <-s.done:
+				return
+			case <-time.After(4 * time.Second):
+			}
+			continue
+		}
+		if done := s.handleReInit(conn); done {
+			break
+		}
+	}
+}
+func (s *SceneService) handleReInit(conn *amqp.Connection) bool {
+	for {
+		s.isReady = false
+		err := s.init(conn)
+		if err != nil {
+			select {
+			case <-s.done:
+				return true
+			case <-time.After(time.Second * 3):
+			}
+			continue
+		}
+		select {
+		case <-s.done:
+			return true
+		case err := <-s.notifyCloseChannel:
+			fmt.Println("Connection closed. Reconnecting..." + err.Error())
+			return false
+		case err := <-s.notifyChanClose:
+			fmt.Println("Channel closed. Re-running init..." + err.Error())
+		}
+	}
+}

+ 37 - 0
services/scene-access/main.go

@@ -0,0 +1,37 @@
+package main
+
+import (
+	"flag"
+	"sparrow/pkg/rpcs"
+	"sparrow/pkg/server"
+	"sparrow/services/scene-access/internal/service"
+)
+
+const (
+	flagRabbitHost    = "rabbithost"
+	defaultRabbitHost = "amqp://guest:guest@localhost:5672/"
+)
+
+var (
+	confRabbitHost = flag.String(flagRabbitHost, defaultRabbitHost, "rabbitmq host address, amqp://user:password@ip:port/")
+)
+
+func main() {
+	// init server
+	err := server.Init(rpcs.SceneAccessServiceName)
+	if err != nil {
+		server.Log.Fatal(err)
+		return
+	}
+	scene := service.NewSceneService(*confRabbitHost)
+
+	err = server.RegisterRPCHandler(scene)
+	if err != nil {
+		return
+	}
+	// start to run
+	err = server.Run()
+	if err != nil {
+		server.Log.Fatal(err)
+	}
+}

+ 45 - 0
services/timer-service/README.md

@@ -0,0 +1,45 @@
+## 定时任务执行服务
+
+监听rabbitmq中的topic为sparrow.task.timer主题的消息,执行定时任务
+
+
+### 消息数据模型
+
+```go
+
+// TimerTaskMessage 定时任务消息
+type TimerTaskMessage struct {
+Cron    string        `json:"cron"`    // 任务执行的cron表达式
+Actions []*TaskAction `json:"actions"` // 执行动作列表
+}
+
+// TaskAction 定时任务执行动作
+type TaskAction struct {
+EntityId string `json:"entity_id"` // 被执行实体Id,指向设备编码
+/*
+	动作对象类型。
+	delay:延时
+	device_issue:设备指令下发
+	device_group_issue:群组指令下发
+*/
+ActionExecutor   string                `json:"action_executor"`   // 动作对象类型。
+ExecutorProperty *TaskExecutorProperty `json:"executor_property"` // 动作执行明细
+}
+
+// TaskExecutorProperty 定时任务执行动作执行参数
+type TaskExecutorProperty struct {
+/*
+	指令 code。当 action_executor 是 device_issue 或 device_group_issue 时,此参数必填。
+*/
+FunctionCode string `json:"function_code"`
+/*
+	指令 value。当 action_executor 是 device_issue 或 device_group_issue 时,此参数必填。
+*/
+FunctionValue bool `json:"function_value"`
+/*
+	延时时间。当 action_executor 是 delay 时,此参数必填。
+*/
+DelaySeconds int64 `json:"delay_seconds"`
+}
+
+```

+ 67 - 0
services/timer-service/internal/executer.go

@@ -0,0 +1,67 @@
+package internal
+
+import (
+	"sparrow/pkg/rpcs"
+	"sparrow/pkg/rule"
+	"sparrow/pkg/server"
+	"time"
+)
+
+// TaskExecutor 任务执行器,用来执行具体的任务动作
+type TaskExecutor struct {
+	Actions []*rule.TaskAction
+}
+
+func NewTaskExecutor(actions []*rule.TaskAction) *TaskExecutor {
+	return &TaskExecutor{
+		Actions: actions,
+	}
+}
+
+func (a *TaskExecutor) Do() error {
+	for _, action := range a.Actions {
+		switch action.ActionExecutor {
+		case "delay":
+			return a.doDelayTask(action.EntityId, action.SubEntityId, action.ExecutorProperty)
+		case "device_issue":
+			return a.doDeviceIssueTask(action.EntityId, action.SubEntityId, action.ExecutorProperty)
+		}
+	}
+	return nil
+}
+
+func (a *TaskExecutor) doDeviceIssueTask(entityId, subEntityId string, action *rule.TaskExecutorProperty) error {
+	// 调用设备接入服务
+	rpchost, err := getAccessRPCHost(entityId)
+	if err != nil {
+		return err
+	}
+	args := rpcs.ArgsSendCommand{
+		DeviceId:  entityId,
+		SubDevice: subEntityId,
+		Cmd:       action.FunctionCode,
+		Params:    action.FunctionValue,
+	}
+	reply := &rpcs.ReplyEmptyResult{}
+	server.Log.Debugf("do Device Issue task args:%v", args)
+	return server.RPCCallByHost(rpchost, "Access.SendCommand", args, reply)
+}
+
+// 执行延时任务
+func (a *TaskExecutor) doDelayTask(entityId, subEntityId string, action *rule.TaskExecutorProperty) error {
+	time.Sleep(time.Duration(action.DelaySeconds) * time.Second)
+	return nil
+}
+
+func getAccessRPCHost(deviceid string) (string, error) {
+	args := rpcs.ArgsGetDeviceOnlineStatus{
+		Id: deviceid,
+	}
+	reply := &rpcs.ReplyGetDeviceOnlineStatus{}
+	err := server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.GetDeviceOnlineStatus", args, reply)
+	if err != nil {
+		return "", err
+	}
+
+	return reply.AccessRPCHost, nil
+}

+ 64 - 0
services/timer-service/internal/scheduler.go

@@ -0,0 +1,64 @@
+package internal
+
+import (
+	"context"
+	"encoding/json"
+	"github.com/gogf/gf/container/gmap"
+	"github.com/gogf/gf/v2/os/gcron"
+	"sparrow/pkg/rule"
+	"sparrow/pkg/server"
+)
+
+// TaskSchedule task schedule 任务调度
+type TaskSchedule struct {
+	tasks *gmap.HashMap // 保存任务名称与任务实体的映射
+}
+
+func NewTaskSchedule() *TaskSchedule {
+	return &TaskSchedule{
+		tasks: gmap.NewHashMap(true),
+	}
+}
+
+func (t *TaskSchedule) AddTask(msg []byte) error {
+	var task rule.TimerTaskMessage
+	err := json.Unmarshal([]byte(msg), &task)
+	if err != nil {
+		return err
+	}
+	// 如果已经存在相同任务Id
+	if t.tasks.Contains(task.TaskId) {
+		return nil
+	}
+	// 创建任务
+	entity, err := gcron.Add(context.Background(), task.Cron, func(ctx context.Context) {
+		if err = NewTaskExecutor(task.Actions).Do(); err != nil {
+			server.Log.Errorf("do taskid :%s error:%s", task.TaskId, err.Error())
+		}
+	}, task.TaskId)
+	if err != nil {
+		return err
+	}
+	t.tasks.Set(task.TaskId, entity)
+	server.Log.Debugf("add a new timer task :%s", task.TaskId)
+	return nil
+}
+
+func (t *TaskSchedule) AddMessageHandle(msg *rule.TaskLifecycleMessage) error {
+	return nil
+}
+
+func (t *TaskSchedule) RemoveMessageHandle(msg *rule.TaskLifecycleMessage) error {
+	server.Log.Debugf("RemoveMessageHandle :%s", msg.TaskId)
+	return nil
+}
+
+func (t *TaskSchedule) UpdateMessageHandle(msg *rule.TaskLifecycleMessage) error {
+	server.Log.Debugf("UpdateMessageHandle :%s", msg.TaskId)
+	return nil
+}
+
+func (t *TaskSchedule) SnapMessageHandle(msg *rule.TaskLifecycleMessage) error {
+	server.Log.Debugf("SnapMessageHandle :%s", msg.TaskId)
+	return nil
+}

+ 149 - 0
services/timer-service/internal/timer_service.go

@@ -0,0 +1,149 @@
+package internal
+
+import (
+	"fmt"
+	"github.com/streadway/amqp"
+	"sparrow/pkg/rpcs"
+	"sparrow/pkg/rule"
+	"sparrow/pkg/server"
+	"time"
+)
+
+type TimerService struct {
+	tc                 *rule.TaskLifecycleConsumer
+	host               string
+	done               chan bool
+	isReady            bool
+	conn               *amqp.Connection
+	notifyCloseChannel chan *amqp.Error
+	notifyChanClose    chan *amqp.Error
+	ch                 *amqp.Channel
+	reconnectChan      chan struct{}
+	taskSchedule       *TaskSchedule
+}
+
+func NewTimerService(host string) *TimerService {
+	ts := &TimerService{
+		host:          host,
+		done:          make(chan bool),
+		taskSchedule:  NewTaskSchedule(),
+		reconnectChan: make(chan struct{}),
+	}
+	go ts.handleReconnect()
+	return ts
+}
+
+func (s *TimerService) Ping(args string, result rpcs.ReplyEmptyResult) error {
+	return nil
+}
+
+func (s *TimerService) init(conn *amqp.Connection) error {
+	ch, err := conn.Channel()
+	if err != nil {
+		return err
+	}
+	s.ch = ch
+	tc := rule.NewTaskLifecycleConsumer(ch)
+	err = tc.Init()
+	if err != nil {
+		return err
+	}
+	err = tc.Start()
+	if err != nil {
+		return err
+	}
+	tc.SetExternalConsumer(s.taskSchedule)
+	s.tc = tc
+	s.notifyChanClose = make(chan *amqp.Error)
+	s.ch.NotifyClose(s.notifyChanClose)
+	s.isReady = true
+	return s.initTaskConsumer()
+}
+
+// 初始化任务消费者
+func (s *TimerService) initTaskConsumer() error {
+	q, err := s.ch.QueueDeclare("", false, true, false, false, nil)
+	if err != nil {
+		return err
+	}
+	err = s.ch.QueueBind(q.Name, "*.*.timer", rule.TaskExchange, false, nil)
+	if err != nil {
+		return err
+	}
+	msgChan, err := s.ch.Consume(q.Name, "", false, false, false, false, nil)
+	if err != nil {
+		return err
+	}
+	go func() {
+		for {
+			select {
+			case <-s.reconnectChan:
+				return
+			case msg := <-msgChan:
+				s.handleTimerTask(msg.Body)
+			}
+		}
+	}()
+	return nil
+}
+
+func (s *TimerService) handleTimerTask(msg []byte) {
+	err := s.taskSchedule.AddTask(msg)
+	if err != nil {
+		server.Log.Errorf("create task error :%s", err.Error())
+	}
+}
+
+func (s *TimerService) connect() (*amqp.Connection, error) {
+	conn, err := amqp.Dial(s.host)
+	if err != nil {
+		return nil, err
+	}
+	s.conn = conn
+	s.notifyCloseChannel = make(chan *amqp.Error)
+	s.conn.NotifyClose(s.notifyCloseChannel)
+	return conn, err
+}
+func (s *TimerService) handleReconnect() {
+	for {
+		s.isReady = false
+		conn, err := s.connect()
+		fmt.Println("handleReconnect")
+		if err != nil {
+			server.Log.Errorf("connect to rabbitmq error:%s", err.Error())
+			select {
+			case <-s.done:
+				return
+			case <-time.After(4 * time.Second):
+			}
+			continue
+		}
+		if done := s.handleReInit(conn); done {
+			break
+		}
+	}
+}
+func (s *TimerService) handleReInit(conn *amqp.Connection) bool {
+	for {
+		s.isReady = false
+		err := s.init(conn)
+		if err != nil {
+			select {
+			case <-s.done:
+				return true
+			case <-time.After(time.Second * 3):
+			}
+			continue
+		}
+		select {
+		case <-s.done:
+			return true
+		case err := <-s.notifyCloseChannel:
+			fmt.Println("Connection closed. Reconnecting..." + err.Error())
+			close(s.reconnectChan)
+			return false
+		case err := <-s.notifyChanClose:
+			fmt.Println("Channel closed. Re-running init..." + err.Error())
+		}
+	}
+}

+ 31 - 0
services/timer-service/main.go

@@ -0,0 +1,31 @@
+package main
+
+import (
+	"flag"
+	"sparrow/pkg/rpcs"
+	"sparrow/pkg/server"
+	"sparrow/services/timer-service/internal"
+)
+
+const (
+	flagRabbitHost    = "rabbithost"
+	defaultRabbitHost = "amqp://guest:guest@localhost:5672/"
+)
+
+var (
+	confRabbitHost = flag.String(flagRabbitHost, defaultRabbitHost, "rabbitmq host address, amqp://user:password@ip:port/")
+)
+
+func main() {
+	// init server
+	err := server.Init(rpcs.TimerServiceName)
+	if err != nil {
+		server.Log.Fatal(err)
+		return
+	}
+	internal.NewTimerService(*confRabbitHost)
+	err = server.Run()
+	if err != nil {
+		server.Log.Fatal(err)
+	}
+}