From 89923bf77a25cb7b0fbc6473e4afb2e4c3021925 Mon Sep 17 00:00:00 2001 From: bergquist Date: Thu, 19 Oct 2017 17:28:54 +0200 Subject: [PATCH 01/39] datasources: change to optimisic concurrency prerequisite for #9504 --- pkg/api/datasources.go | 26 ++++-- pkg/api/dtos/datasource.go | 59 ++++++++++++ pkg/api/dtos/models.go | 50 ----------- pkg/models/datasource.go | 13 +-- pkg/services/sqlstore/datasource.go | 20 ++++- pkg/services/sqlstore/datasource_test.go | 90 +++++++++++++++++-- .../sqlstore/migrations/datasource_mig.go | 6 ++ public/app/features/plugins/ds_edit_ctrl.ts | 4 +- 8 files changed, 196 insertions(+), 72 deletions(-) create mode 100644 pkg/api/dtos/datasource.go diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index 9ffdc4a6d1b..7c509499981 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -119,7 +119,13 @@ func AddDataSource(c *middleware.Context, cmd m.AddDataSourceCommand) { return } - c.JSON(200, util.DynMap{"message": "Datasource added", "id": cmd.Result.Id, "name": cmd.Result.Name}) + ds := convertModelToDtos(cmd.Result) + c.JSON(200, util.DynMap{ + "message": "Datasource added", + "id": cmd.Result.Id, + "name": cmd.Result.Name, + "datasource": ds, + }) } func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) Response { @@ -133,10 +139,19 @@ func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) Resp err = bus.Dispatch(&cmd) if err != nil { - return ApiError(500, "Failed to update datasource", err) + if err == m.ErrDataSouceUpdatingOldVersion { + return ApiError(500, "Failed to update datasource. Reload new version and try again", err) + } else { + return ApiError(500, "Failed to update datasource", err) + } } - - return Json(200, util.DynMap{"message": "Datasource updated", "id": cmd.Id, "name": cmd.Name}) + ds := convertModelToDtos(cmd.Result) + return Json(200, util.DynMap{ + "message": "Datasource updated", + "id": cmd.Id, + "name": cmd.Name, + "datasource": ds, + }) } func fillWithSecureJsonData(cmd *m.UpdateDataSourceCommand) error { @@ -158,8 +173,6 @@ func fillWithSecureJsonData(cmd *m.UpdateDataSourceCommand) error { } } - // set version from db - cmd.Version = ds.Version return nil } @@ -228,6 +241,7 @@ func convertModelToDtos(ds *m.DataSource) dtos.DataSource { IsDefault: ds.IsDefault, JsonData: ds.JsonData, SecureJsonFields: map[string]bool{}, + Version: ds.Version, } for k, v := range ds.SecureJsonData { diff --git a/pkg/api/dtos/datasource.go b/pkg/api/dtos/datasource.go new file mode 100644 index 00000000000..7cb36e61ab4 --- /dev/null +++ b/pkg/api/dtos/datasource.go @@ -0,0 +1,59 @@ +package dtos + +import ( + "strings" + + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" +) + +type DataSource struct { + Id int64 `json:"id"` + OrgId int64 `json:"orgId"` + Name string `json:"name"` + Type string `json:"type"` + TypeLogoUrl string `json:"typeLogoUrl"` + Access m.DsAccess `json:"access"` + Url string `json:"url"` + Password string `json:"password"` + User string `json:"user"` + Database string `json:"database"` + BasicAuth bool `json:"basicAuth"` + BasicAuthUser string `json:"basicAuthUser"` + BasicAuthPassword string `json:"basicAuthPassword"` + WithCredentials bool `json:"withCredentials"` + IsDefault bool `json:"isDefault"` + JsonData *simplejson.Json `json:"jsonData,omitempty"` + SecureJsonFields map[string]bool `json:"secureJsonFields"` + Version int `json:"version"` +} + +type DataSourceListItemDTO struct { + Id int64 `json:"id"` + OrgId int64 `json:"orgId"` + Name string `json:"name"` + Type string `json:"type"` + TypeLogoUrl string `json:"typeLogoUrl"` + Access m.DsAccess `json:"access"` + Url string `json:"url"` + Password string `json:"password"` + User string `json:"user"` + Database string `json:"database"` + BasicAuth bool `json:"basicAuth"` + IsDefault bool `json:"isDefault"` + JsonData *simplejson.Json `json:"jsonData,omitempty"` +} + +type DataSourceList []DataSourceListItemDTO + +func (slice DataSourceList) Len() int { + return len(slice) +} + +func (slice DataSourceList) Less(i, j int) bool { + return strings.ToLower(slice[i].Name) < strings.ToLower(slice[j].Name) +} + +func (slice DataSourceList) Swap(i, j int) { + slice[i], slice[j] = slice[j], slice[i] +} diff --git a/pkg/api/dtos/models.go b/pkg/api/dtos/models.go index d1c346e9539..e2aa12249aa 100644 --- a/pkg/api/dtos/models.go +++ b/pkg/api/dtos/models.go @@ -37,56 +37,6 @@ type CurrentUser struct { HelpFlags1 m.HelpFlags1 `json:"helpFlags1"` } -type DataSource struct { - Id int64 `json:"id"` - OrgId int64 `json:"orgId"` - Name string `json:"name"` - Type string `json:"type"` - TypeLogoUrl string `json:"typeLogoUrl"` - Access m.DsAccess `json:"access"` - Url string `json:"url"` - Password string `json:"password"` - User string `json:"user"` - Database string `json:"database"` - BasicAuth bool `json:"basicAuth"` - BasicAuthUser string `json:"basicAuthUser"` - BasicAuthPassword string `json:"basicAuthPassword"` - WithCredentials bool `json:"withCredentials"` - IsDefault bool `json:"isDefault"` - JsonData *simplejson.Json `json:"jsonData,omitempty"` - SecureJsonFields map[string]bool `json:"secureJsonFields"` -} - -type DataSourceListItemDTO struct { - Id int64 `json:"id"` - OrgId int64 `json:"orgId"` - Name string `json:"name"` - Type string `json:"type"` - TypeLogoUrl string `json:"typeLogoUrl"` - Access m.DsAccess `json:"access"` - Url string `json:"url"` - Password string `json:"password"` - User string `json:"user"` - Database string `json:"database"` - BasicAuth bool `json:"basicAuth"` - IsDefault bool `json:"isDefault"` - JsonData *simplejson.Json `json:"jsonData,omitempty"` -} - -type DataSourceList []DataSourceListItemDTO - -func (slice DataSourceList) Len() int { - return len(slice) -} - -func (slice DataSourceList) Less(i, j int) bool { - return strings.ToLower(slice[i].Name) < strings.ToLower(slice[j].Name) -} - -func (slice DataSourceList) Swap(i, j int) { - slice[i], slice[j] = slice[j], slice[i] -} - type MetricRequest struct { From string `json:"from"` To string `json:"to"` diff --git a/pkg/models/datasource.go b/pkg/models/datasource.go index ee365582734..f600da75a63 100644 --- a/pkg/models/datasource.go +++ b/pkg/models/datasource.go @@ -25,8 +25,9 @@ const ( // Typed errors var ( - ErrDataSourceNotFound = errors.New("Data source not found") - ErrDataSourceNameExists = errors.New("Data source with same name already exists") + ErrDataSourceNotFound = errors.New("Data source not found") + ErrDataSourceNameExists = errors.New("Data source with same name already exists") + ErrDataSouceUpdatingOldVersion = errors.New("Trying to update old version of datasouce") ) type DsAccess string @@ -131,10 +132,12 @@ type UpdateDataSourceCommand struct { IsDefault bool `json:"isDefault"` JsonData *simplejson.Json `json:"jsonData"` SecureJsonData map[string]string `json:"secureJsonData"` + Version int `json:"version"` - OrgId int64 `json:"-"` - Id int64 `json:"-"` - Version int `json:"-"` + OrgId int64 `json:"-"` + Id int64 `json:"-"` + + Result *DataSource } type DeleteDataSourceByIdCommand struct { diff --git a/pkg/services/sqlstore/datasource.go b/pkg/services/sqlstore/datasource.go index 88dc34fd196..3b4bef61a1d 100644 --- a/pkg/services/sqlstore/datasource.go +++ b/pkg/services/sqlstore/datasource.go @@ -3,6 +3,8 @@ package sqlstore import ( "time" + "github.com/go-xorm/xorm" + "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/securejsondata" "github.com/grafana/grafana/pkg/metrics" @@ -69,7 +71,6 @@ func DeleteDataSourceByName(cmd *m.DeleteDataSourceByNameCommand) error { } func AddDataSource(cmd *m.AddDataSourceCommand) error { - return inTransaction(func(sess *DBSession) error { existing := m.DataSource{OrgId: cmd.OrgId, Name: cmd.Name} has, _ := sess.Get(&existing) @@ -96,6 +97,7 @@ func AddDataSource(cmd *m.AddDataSourceCommand) error { SecureJsonData: securejsondata.GetEncryptedJsonData(cmd.SecureJsonData), Created: time.Now(), Updated: time.Now(), + Version: 1, } if _, err := sess.Insert(ds); err != nil { @@ -122,7 +124,6 @@ func updateIsDefaultFlag(ds *m.DataSource, sess *DBSession) error { } func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error { - return inTransaction(func(sess *DBSession) error { ds := &m.DataSource{ Id: cmd.Id, @@ -149,12 +150,25 @@ func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error { sess.UseBool("basic_auth") sess.UseBool("with_credentials") - _, err := sess.Where("id=? and org_id=?", ds.Id, ds.OrgId).Update(ds) + var updateSession *xorm.Session + if cmd.Version != 0 { + updateSession = sess.Where("id=? and org_id=? and (version = ? or version < ?)", ds.Id, ds.OrgId, cmd.Version, cmd.Version) + } else { + updateSession = sess.Where("id=? and org_id=?", ds.Id, ds.OrgId) + } + + affected, err := updateSession.Update(ds) if err != nil { return err } + if affected == 0 { + return m.ErrDataSouceUpdatingOldVersion + } + err = updateIsDefaultFlag(ds, sess) + + cmd.Result = ds return err }) } diff --git a/pkg/services/sqlstore/datasource_test.go b/pkg/services/sqlstore/datasource_test.go index 51bc759fdaf..f7a0ab7c1e2 100644 --- a/pkg/services/sqlstore/datasource_test.go +++ b/pkg/services/sqlstore/datasource_test.go @@ -35,12 +35,9 @@ type Test struct { } func TestDataAccess(t *testing.T) { - Convey("Testing DB", t, func() { InitTestDB(t) - Convey("Can add datasource", func() { - err := AddDataSource(&m.AddDataSourceCommand{ OrgId: 10, Name: "laban", @@ -65,7 +62,6 @@ func TestDataAccess(t *testing.T) { }) Convey("Given a datasource", func() { - err := AddDataSource(&m.AddDataSourceCommand{ OrgId: 10, Name: "nisse", @@ -81,6 +77,89 @@ func TestDataAccess(t *testing.T) { ds := query.Result[0] + Convey(" updated ", func() { + cmd := &m.UpdateDataSourceCommand{ + Id: ds.Id, + OrgId: 10, + Name: "nisse", + Type: m.DS_GRAPHITE, + Access: m.DS_ACCESS_PROXY, + Url: "http://test", + Version: ds.Version, + } + + Convey("with same version as source", func() { + err := UpdateDataSource(cmd) + So(err, ShouldBeNil) + }) + + Convey("when someone else updated between read and update", func() { + query := m.GetDataSourcesQuery{OrgId: 10} + err = GetDataSources(&query) + So(err, ShouldBeNil) + + ds := query.Result[0] + intendedUpdate := &m.UpdateDataSourceCommand{ + Id: ds.Id, + OrgId: 10, + Name: "nisse", + Type: m.DS_GRAPHITE, + Access: m.DS_ACCESS_PROXY, + Url: "http://test", + Version: ds.Version, + } + + updateFromOtherUser := &m.UpdateDataSourceCommand{ + Id: ds.Id, + OrgId: 10, + Name: "nisse", + Type: m.DS_GRAPHITE, + Access: m.DS_ACCESS_PROXY, + Url: "http://test", + Version: ds.Version, + } + + err := UpdateDataSource(updateFromOtherUser) + So(err, ShouldBeNil) + + err = UpdateDataSource(intendedUpdate) + So(err, ShouldNotBeNil) + }) + + Convey("updating datasource without version", func() { + cmd := &m.UpdateDataSourceCommand{ + Id: ds.Id, + OrgId: 10, + Name: "nisse", + Type: m.DS_GRAPHITE, + Access: m.DS_ACCESS_PROXY, + Url: "http://test", + } + + Convey("should not raise errors", func() { + err := UpdateDataSource(cmd) + So(err, ShouldBeNil) + }) + }) + + Convey("updating datasource without higher version", func() { + cmd := &m.UpdateDataSourceCommand{ + Id: ds.Id, + OrgId: 10, + Name: "nisse", + Type: m.DS_GRAPHITE, + Access: m.DS_ACCESS_PROXY, + Url: "http://test", + Version: 90000, + } + + Convey("should not raise errors", func() { + err := UpdateDataSource(cmd) + So(err, ShouldBeNil) + }) + }) + }) + Convey("Can delete datasource by id", func() { err := DeleteDataSourceById(&m.DeleteDataSourceByIdCommand{Id: ds.Id, OrgId: ds.OrgId}) So(err, ShouldBeNil) @@ -104,9 +183,6 @@ func TestDataAccess(t *testing.T) { GetDataSources(&query) So(len(query.Result), ShouldEqual, 1) }) - }) - }) - } diff --git a/pkg/services/sqlstore/migrations/datasource_mig.go b/pkg/services/sqlstore/migrations/datasource_mig.go index c694b5b7cfb..cc8a7f05177 100644 --- a/pkg/services/sqlstore/migrations/datasource_mig.go +++ b/pkg/services/sqlstore/migrations/datasource_mig.go @@ -120,4 +120,10 @@ func addDataSourceMigration(mg *Migrator) { {Name: "json_data", Type: DB_Text, Nullable: true}, {Name: "secure_json_data", Type: DB_Text, Nullable: true}, })) + + const setVersionToOneWhereZero = `UPDATE data_source SET version = 1 WHERE version = 0` + mg.AddMigration("Update initial version to 1", new(RawSqlMigration). + Sqlite(setVersionToOneWhereZero). + Postgres(setVersionToOneWhereZero). + Mysql(setVersionToOneWhereZero)) } diff --git a/public/app/features/plugins/ds_edit_ctrl.ts b/public/app/features/plugins/ds_edit_ctrl.ts index 0513487dce7..d388783400d 100644 --- a/public/app/features/plugins/ds_edit_ctrl.ts +++ b/public/app/features/plugins/ds_edit_ctrl.ts @@ -150,13 +150,15 @@ export class DataSourceEditCtrl { } if (this.current.id) { - return this.backendSrv.put('/api/datasources/' + this.current.id, this.current).then(() => { + return this.backendSrv.put('/api/datasources/' + this.current.id, this.current).then((result) => { + this.current = result.datasource; this.updateFrontendSettings().then(() => { this.testDatasource(); }); }); } else { return this.backendSrv.post('/api/datasources', this.current).then(result => { + this.current = result.datasource; this.updateFrontendSettings(); datasourceCreated = true; From 5f0a86be4c612ad15b1f289ecb6106b234d1d9c3 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 24 Oct 2017 10:21:40 +0200 Subject: [PATCH 02/39] changelog: adds note about closing #9636 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcacc92e542..7abc23dbcb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ ## Fixes * **Sensu**: Send alert message to sensu output [#9551](https://github.com/grafana/grafana/issues/9551), thx [@cjchand](https://github.com/cjchand) +* **Singlestat**: suppress error when result contains no datapoints [#9636](https://github.com/grafana/grafana/issues/9636), thx [@utkarshcmu](https://github.com/utkarshcmu) # 4.6.0-beta3 (2017-10-23) From beb203209b6d7b2236995434ddcd47f346d27ab8 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 24 Oct 2017 10:34:53 +0200 Subject: [PATCH 03/39] prom: adds pre built grafana dashboard --- .../prometheus/dashboards/grafana_stats.json | 1052 +++++++++++++++++ .../plugins/datasource/prometheus/plugin.json | 3 +- 2 files changed, 1054 insertions(+), 1 deletion(-) create mode 100644 public/app/plugins/datasource/prometheus/dashboards/grafana_stats.json diff --git a/public/app/plugins/datasource/prometheus/dashboards/grafana_stats.json b/public/app/plugins/datasource/prometheus/dashboards/grafana_stats.json new file mode 100644 index 00000000000..aa9384a907d --- /dev/null +++ b/public/app/plugins/datasource/prometheus/dashboards/grafana_stats.json @@ -0,0 +1,1052 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "4.6.0" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "revision": "1.0", + "version": 2, + "title": "Grafana metrics", + "tags": [ + "grafana", + "prometheus" + ], + "description": "Metrics about Grafana", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ + { + "icon": "external link", + "tags": [], + "targetBlank": true, + "title": "Available metrics", + "type": "link", + "url": "/metrics" + }, + { + "icon": "external link", + "tags": [], + "title": "Grafana docs", + "type": "link", + "url": "http://docs.grafana.org/" + }, + { + "icon": "external link", + "tags": [], + "title": "Prometheus docs", + "type": "link", + "url": "http://prometheus.io/docs/introduction/overview/" + } + ], + "rows": [ + { + "collapse": false, + "height": 164, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "rgba(222, 3, 3, 0.9)", + "rgb(234, 245, 234)", + "rgb(235, 244, 235)" + ], + "datasource": "${DS_PROMETHEUS}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "up{job=\"grafana\"}", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A", + "step": 60 + } + ], + "thresholds": "1, 10000", + "title": "Active instances", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": ":(", + "value": "0" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 8, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "grafana_stat_totals_dashboard", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A", + "step": 60 + } + ], + "thresholds": "", + "title": "Dashboard count", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 9, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "grafana_stat_total_users", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A", + "step": 60 + } + ], + "thresholds": "", + "title": "User count", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_PROMETHEUS}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 10, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "grafana_stat_total_playlists", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A", + "step": 60 + } + ], + "thresholds": "", + "title": "Playlist count", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "id": 17, + "links": [], + "pageSize": null, + "scroll": false, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "span": 2, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 0, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "topk(1, grafana_info)", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "legendFormat": "{{version}}", + "refId": "A", + "step": 20 + } + ], + "title": "Grafana version", + "transform": "timeseries_to_rows", + "type": "table" + }, + { + "content": "
\n
\n
\n\n💖\n\"Prometheus\n
", + "id": 16, + "links": [], + "mode": "html", + "span": 2, + "title": "", + "transparent": true, + "type": "text" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 373, + "panels": [ + { + "aliasColors": { + "400": "#447EBC", + "500": "#BF1B00" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "height": "", + "id": 15, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + {} + ], + "spaceLength": 10, + "span": 5, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (statuscode) (irate(http_request_total{job='grafana'}[5m]))", + "format": "time_series", + "intervalFactor": 3, + "legendFormat": "{{statuscode}}", + "refId": "B", + "step": 15, + "target": "dev.grafana.cb-office.alerting.active_alerts" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "http status codes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + "400": "#447EBC", + "500": "#BF1B00" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "height": "", + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + {} + ], + "spaceLength": 10, + "span": 5, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(grafana_api_response_status_total[5m]))", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "api", + "refId": "A", + "step": 20 + }, + { + "expr": "sum(irate(grafana_proxy_response_status_total[5m]))", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "proxy", + "refId": "B", + "step": 20 + }, + { + "expr": "sum(irate(grafana_page_response_status_total[5m]))", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "web", + "refId": "C", + "step": 20 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Requests by routing group", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "columns": [], + "datasource": "${DS_PROMETHEUS}", + "fontSize": "100%", + "height": "", + "id": 12, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "span": 2, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 0, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sort(topk(8, sum by (handler) (http_request_total{job=\"grafana\"})))", + "format": "time_series", + "instant": true, + "intervalFactor": 10, + "legendFormat": "{{handler}}", + "refId": "A", + "step": 100 + } + ], + "title": "Most used handlers", + "transform": "timeseries_to_rows", + "type": "table" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 188, + "panels": [ + { + "aliasColors": { + "alerting": "#890F02", + "ok": "#7EB26D" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "increase(grafana_alerting_result_total[1m])", + "format": "time_series", + "intervalFactor": 3, + "legendFormat": "{{state}}", + "refId": "A", + "step": 15 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Grafana alert results", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + "alerting": "#890F02", + "alertname": "#BF1B00", + "firing alerts": "#BF1B00", + "ok": "#7EB26D" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "fill": 1, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Firing alerts", + "yaxis": 1 + } + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": " sum (ALERTS)", + "format": "time_series", + "intervalFactor": 3, + "legendFormat": "firing alerts", + "refId": "A", + "step": 15 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Prometheus alerts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 250, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMETHEUS}", + "description": "Aggregated over all Grafana nodes.", + "fill": 1, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "avg gc duration", + "yaxis": 2 + }, + { + "alias": "127.0.0.1:3000", + "yaxis": 1 + }, + { + "alias": "allocated memory", + "yaxis": 2 + }, + { + "alias": "used memory", + "yaxis": 2 + }, + { + "alias": "memory usage", + "yaxis": 2 + } + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(go_goroutines{job=\"grafana\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 4, + "legendFormat": "go routines", + "refId": "A", + "step": 8, + "target": "select metric", + "type": "timeserie" + }, + { + "expr": "sum(process_resident_memory_bytes{job=\"grafana\"})", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "memory usage", + "refId": "B", + "step": 8 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Grafana performance", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "" + } \ No newline at end of file diff --git a/public/app/plugins/datasource/prometheus/plugin.json b/public/app/plugins/datasource/prometheus/plugin.json index 43bb0c53595..bd19462579b 100644 --- a/public/app/plugins/datasource/prometheus/plugin.json +++ b/public/app/plugins/datasource/prometheus/plugin.json @@ -4,7 +4,8 @@ "id": "prometheus", "includes": [ - {"type": "dashboard", "name": "Prometheus Stats", "path": "dashboards/prometheus_stats.json"} + {"type": "dashboard", "name": "Prometheus Stats", "path": "dashboards/prometheus_stats.json"}, + {"type": "dashboard", "name": "Grafana Stats", "path": "dashboards/grafana_stats.json"} ], "metrics": true, From 9b6535cca107f0f922d97c070ea2d41095adf689 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 24 Oct 2017 11:00:23 +0200 Subject: [PATCH 04/39] alerting: only editors can pause rules closes #9640 --- pkg/api/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 8c91120facc..ba5e7ae4e10 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -267,7 +267,7 @@ func (hs *HttpServer) registerRoutes() { apiRoute.Group("/alerts", func(alertsRoute RouteRegister) { alertsRoute.Post("/test", bind(dtos.AlertTestCommand{}), wrap(AlertTest)) - alertsRoute.Post("/:alertId/pause", bind(dtos.PauseAlertCommand{}), wrap(PauseAlert), reqEditorRole) + alertsRoute.Post("/:alertId/pause", reqEditorRole, bind(dtos.PauseAlertCommand{}), wrap(PauseAlert)) alertsRoute.Get("/:alertId", ValidateOrgAlert, wrap(GetAlert)) alertsRoute.Get("/", wrap(GetAlerts)) alertsRoute.Get("/states-for-dashboard", wrap(GetAlertStatesForDashboard)) From 5a53051f72335e71144d0b39ac70e84af8c38e89 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 24 Oct 2017 11:08:34 +0200 Subject: [PATCH 05/39] changelog: adds note about closing #9640 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7abc23dbcb4..5c432e9defe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,11 @@ * **Sensu**: Send alert message to sensu output [#9551](https://github.com/grafana/grafana/issues/9551), thx [@cjchand](https://github.com/cjchand) * **Singlestat**: suppress error when result contains no datapoints [#9636](https://github.com/grafana/grafana/issues/9636), thx [@utkarshcmu](https://github.com/utkarshcmu) +# 4.6.0-beta4 (unreleased) + +## Fixes +* **Alerting**: Viewer can no longer pause alert rules [#9640](https://github.com/grafana/grafana/issues/9640) + # 4.6.0-beta3 (2017-10-23) ## Fixes From 8070a7ca3581cebc8476916fdb381d82b7612b5d Mon Sep 17 00:00:00 2001 From: Nadezhda Mosunova Date: Tue, 24 Oct 2017 14:18:47 +0300 Subject: [PATCH 06/39] Update development.md --- docs/sources/plugins/developing/development.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/plugins/developing/development.md b/docs/sources/plugins/developing/development.md index 41cef41b653..f2e70a50c6a 100644 --- a/docs/sources/plugins/developing/development.md +++ b/docs/sources/plugins/developing/development.md @@ -16,7 +16,7 @@ You can extend Grafana by writing your own plugins and then share then with othe 1. [Setup grafana](http://docs.grafana.org/project/building_from_source/) 2. Clone an example plugin into ```/var/lib/grafana/plugins``` or `data/plugins` (relative to grafana git repo if you're running development version from source dir) -3. You one of our example plugins as starting point +3. Use one of our example plugins as starting point Example plugins From 2f35759346fc6d7985d004e8b0ef28c94b6a90c4 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 24 Oct 2017 13:40:03 +0200 Subject: [PATCH 07/39] asscoiate comment with name --- pkg/services/alerting/eval_handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/alerting/eval_handler.go b/pkg/services/alerting/eval_handler.go index 5c2861b9154..79b2f231b41 100644 --- a/pkg/services/alerting/eval_handler.go +++ b/pkg/services/alerting/eval_handler.go @@ -67,7 +67,7 @@ func (e *DefaultEvalHandler) Eval(context *EvalContext) { metrics.M_Alerting_Execution_Time.Observe(float64(elapsedTime)) } -// This should be move into evalContext once its been refactored. +// This should be move into evalContext once its been refactored. (Carl Bergquist) func (handler *DefaultEvalHandler) getNewState(evalContext *EvalContext) models.AlertStateType { if evalContext.Error != nil { handler.log.Error("Alert Rule Result Error", From 56e53b83431a008b0d6f63935c5066b6b9606de3 Mon Sep 17 00:00:00 2001 From: Sven Klemm <31455525+svenklemm@users.noreply.github.com> Date: Tue, 24 Oct 2017 14:05:41 +0200 Subject: [PATCH 08/39] dont quote variables for mysql and postgres datasource (#9611) --- .../plugins/datasource/mysql/datasource.ts | 2 +- .../mysql/specs/datasource_specs.ts | 4 ++-- .../plugins/datasource/postgres/datasource.ts | 4 ++-- .../postgres/specs/datasource_specs.ts | 20 +++++++++++++++++++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/public/app/plugins/datasource/mysql/datasource.ts b/public/app/plugins/datasource/mysql/datasource.ts index 6a255d63d52..e35896c0d04 100644 --- a/public/app/plugins/datasource/mysql/datasource.ts +++ b/public/app/plugins/datasource/mysql/datasource.ts @@ -17,7 +17,7 @@ export class MysqlDatasource { interpolateVariable(value) { if (typeof value === 'string') { - return '\'' + value + '\''; + return value; } if (typeof value === 'number') { diff --git a/public/app/plugins/datasource/mysql/specs/datasource_specs.ts b/public/app/plugins/datasource/mysql/specs/datasource_specs.ts index 6ff1f9d47ac..f579ad15410 100644 --- a/public/app/plugins/datasource/mysql/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/mysql/specs/datasource_specs.ts @@ -196,8 +196,8 @@ describe('MySQLDatasource', function() { describe('When interpolating variables', () => { describe('and value is a string', () => { - it('should return a quoted value', () => { - expect(ctx.ds.interpolateVariable('abc')).to.eql('\'abc\''); + it('should return an unquoted value', () => { + expect(ctx.ds.interpolateVariable('abc')).to.eql('abc'); }); }); diff --git a/public/app/plugins/datasource/postgres/datasource.ts b/public/app/plugins/datasource/postgres/datasource.ts index d75aecbc281..68471f035ff 100644 --- a/public/app/plugins/datasource/postgres/datasource.ts +++ b/public/app/plugins/datasource/postgres/datasource.ts @@ -17,11 +17,11 @@ export class PostgresDatasource { interpolateVariable(value) { if (typeof value === 'string') { - return '\'' + value + '\''; + return value; } if (typeof value === 'number') { - return value.toString(); + return value; } var quotedValues = _.map(value, function(val) { diff --git a/public/app/plugins/datasource/postgres/specs/datasource_specs.ts b/public/app/plugins/datasource/postgres/specs/datasource_specs.ts index 5510e138f63..3f83bb76e7b 100644 --- a/public/app/plugins/datasource/postgres/specs/datasource_specs.ts +++ b/public/app/plugins/datasource/postgres/specs/datasource_specs.ts @@ -193,4 +193,24 @@ describe('PostgreSQLDatasource', function() { expect(results[0].value).to.be('same'); }); }); + + describe('When interpolating variables', () => { + describe('and value is a string', () => { + it('should return an unquoted value', () => { + expect(ctx.ds.interpolateVariable('abc')).to.eql('abc'); + }); + }); + + describe('and value is a number', () => { + it('should return an unquoted value', () => { + expect(ctx.ds.interpolateVariable(1000)).to.eql(1000); + }); + }); + + describe('and value is an array of strings', () => { + it('should return comma separated quoted values', () => { + expect(ctx.ds.interpolateVariable(['a', 'b', 'c'])).to.eql('\'a\',\'b\',\'c\''); + }); + }); + }); }); From 8334b24b4274aee5ba9e63cefae0c5654bd3f696 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 24 Oct 2017 14:09:33 +0200 Subject: [PATCH 09/39] changelog: note for #9030 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c432e9defe..81ec87a58f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ## Fixes * **Sensu**: Send alert message to sensu output [#9551](https://github.com/grafana/grafana/issues/9551), thx [@cjchand](https://github.com/cjchand) * **Singlestat**: suppress error when result contains no datapoints [#9636](https://github.com/grafana/grafana/issues/9636), thx [@utkarshcmu](https://github.com/utkarshcmu) +* **Postgres/MySQL**: Control quoting in SQL-queries when using template variables [9030](https://github.com/grafana/grafana/issues/9030), thanks [@svenklemm](https://github.com/svenklemm) # 4.6.0-beta4 (unreleased) From dea631bedca9f24c86cd4b3ce56f27c917c3382c Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 24 Oct 2017 14:09:39 +0200 Subject: [PATCH 10/39] tech: remove rabbitmq event publisher closes #9645 --- conf/defaults.ini | 7 - conf/sample.ini | 6 - docs/sources/http_api/admin.md | 5 - pkg/cmd/grafana-server/server.go | 2 - pkg/services/eventpublisher/eventpublisher.go | 150 - vendor/github.com/streadway/amqp/.gitignore | 3 - vendor/github.com/streadway/amqp/.travis.yml | 13 - vendor/github.com/streadway/amqp/LICENSE | 23 - vendor/github.com/streadway/amqp/README.md | 76 - vendor/github.com/streadway/amqp/allocator.go | 106 - .../streadway/amqp/allocator_test.go | 90 - vendor/github.com/streadway/amqp/auth.go | 44 - vendor/github.com/streadway/amqp/certs.sh | 159 - vendor/github.com/streadway/amqp/channel.go | 1589 -------- .../github.com/streadway/amqp/client_test.go | 559 --- .../github.com/streadway/amqp/connection.go | 764 ---- vendor/github.com/streadway/amqp/consumers.go | 118 - vendor/github.com/streadway/amqp/delivery.go | 173 - .../streadway/amqp/delivery_test.go | 33 - vendor/github.com/streadway/amqp/doc.go | 108 - .../streadway/amqp/examples_test.go | 395 -- vendor/github.com/streadway/amqp/gen.sh | 2 - .../streadway/amqp/integration_test.go | 1772 --------- vendor/github.com/streadway/amqp/read.go | 444 --- .../streadway/amqp/reconnect_test.go | 113 - vendor/github.com/streadway/amqp/return.go | 64 - .../github.com/streadway/amqp/shared_test.go | 71 - .../amqp/spec/amqp0-9-1.stripped.extended.xml | 537 --- vendor/github.com/streadway/amqp/spec/gen.go | 536 --- vendor/github.com/streadway/amqp/spec091.go | 3306 ----------------- vendor/github.com/streadway/amqp/tls_test.go | 218 -- vendor/github.com/streadway/amqp/types.go | 382 -- vendor/github.com/streadway/amqp/uri.go | 170 - vendor/github.com/streadway/amqp/uri_test.go | 328 -- vendor/github.com/streadway/amqp/write.go | 411 -- 35 files changed, 12777 deletions(-) delete mode 100644 pkg/services/eventpublisher/eventpublisher.go delete mode 100644 vendor/github.com/streadway/amqp/.gitignore delete mode 100644 vendor/github.com/streadway/amqp/.travis.yml delete mode 100644 vendor/github.com/streadway/amqp/LICENSE delete mode 100644 vendor/github.com/streadway/amqp/README.md delete mode 100644 vendor/github.com/streadway/amqp/allocator.go delete mode 100644 vendor/github.com/streadway/amqp/allocator_test.go delete mode 100644 vendor/github.com/streadway/amqp/auth.go delete mode 100644 vendor/github.com/streadway/amqp/certs.sh delete mode 100644 vendor/github.com/streadway/amqp/channel.go delete mode 100644 vendor/github.com/streadway/amqp/client_test.go delete mode 100644 vendor/github.com/streadway/amqp/connection.go delete mode 100644 vendor/github.com/streadway/amqp/consumers.go delete mode 100644 vendor/github.com/streadway/amqp/delivery.go delete mode 100644 vendor/github.com/streadway/amqp/delivery_test.go delete mode 100644 vendor/github.com/streadway/amqp/doc.go delete mode 100644 vendor/github.com/streadway/amqp/examples_test.go delete mode 100644 vendor/github.com/streadway/amqp/gen.sh delete mode 100644 vendor/github.com/streadway/amqp/integration_test.go delete mode 100644 vendor/github.com/streadway/amqp/read.go delete mode 100644 vendor/github.com/streadway/amqp/reconnect_test.go delete mode 100644 vendor/github.com/streadway/amqp/return.go delete mode 100644 vendor/github.com/streadway/amqp/shared_test.go delete mode 100644 vendor/github.com/streadway/amqp/spec/amqp0-9-1.stripped.extended.xml delete mode 100644 vendor/github.com/streadway/amqp/spec/gen.go delete mode 100644 vendor/github.com/streadway/amqp/spec091.go delete mode 100644 vendor/github.com/streadway/amqp/tls_test.go delete mode 100644 vendor/github.com/streadway/amqp/types.go delete mode 100644 vendor/github.com/streadway/amqp/uri.go delete mode 100644 vendor/github.com/streadway/amqp/uri_test.go delete mode 100644 vendor/github.com/streadway/amqp/write.go diff --git a/conf/defaults.ini b/conf/defaults.ini index 14e77449241..404a7950bf3 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -381,13 +381,6 @@ facility = # Syslog tag. By default, the process' argv[0] is used. tag = - -#################################### AMQP Event Publisher ################ -[event_publisher] -enabled = false -rabbitmq_url = amqp://localhost/ -exchange = grafana_events - #################################### Dashboard JSON files ################ [dashboards.json] enabled = false diff --git a/conf/sample.ini b/conf/sample.ini index 1aedfbf6532..c7d2d1d2695 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -360,12 +360,6 @@ ;tag = -#################################### AMQP Event Publisher ########################## -[event_publisher] -;enabled = false -;rabbitmq_url = amqp://localhost/ -;exchange = grafana_events - ;#################################### Dashboard JSON files ########################## [dashboards.json] ;enabled = false diff --git a/docs/sources/http_api/admin.md b/docs/sources/http_api/admin.md index 3ef5fb1136a..716246102bc 100644 --- a/docs/sources/http_api/admin.md +++ b/docs/sources/http_api/admin.md @@ -102,11 +102,6 @@ Content-Type: application/json "templates_pattern":"emails/*.html", "welcome_email_on_sign_up":"false" }, - "event_publisher":{ - "enabled":"false", - "exchange":"grafana_events", - "rabbitmq_url":"amqp://localhost/" - }, "log":{ "buffer_len":"10000", "level":"Info", diff --git a/pkg/cmd/grafana-server/server.go b/pkg/cmd/grafana-server/server.go index f6a94ac6ef0..4bbabbe3273 100644 --- a/pkg/cmd/grafana-server/server.go +++ b/pkg/cmd/grafana-server/server.go @@ -19,7 +19,6 @@ import ( "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/cleanup" - "github.com/grafana/grafana/pkg/services/eventpublisher" "github.com/grafana/grafana/pkg/services/notifications" "github.com/grafana/grafana/pkg/services/search" "github.com/grafana/grafana/pkg/setting" @@ -59,7 +58,6 @@ func (g *GrafanaServerImpl) Start() { search.Init() login.Init() social.NewOAuthService() - eventpublisher.Init() plugins.Init() closer, err := tracing.Init(setting.Cfg) diff --git a/pkg/services/eventpublisher/eventpublisher.go b/pkg/services/eventpublisher/eventpublisher.go deleted file mode 100644 index 2854b63a9a5..00000000000 --- a/pkg/services/eventpublisher/eventpublisher.go +++ /dev/null @@ -1,150 +0,0 @@ -package eventpublisher - -import ( - "encoding/json" - "fmt" - "log" - "time" - - "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/events" - "github.com/grafana/grafana/pkg/setting" - "github.com/streadway/amqp" -) - -var ( - url string - exchange string - conn *amqp.Connection - channel *amqp.Channel -) - -func getConnection() (*amqp.Connection, error) { - c, err := amqp.Dial(url) - if err != nil { - return nil, err - } - return c, err -} - -func getChannel() (*amqp.Channel, error) { - ch, err := conn.Channel() - if err != nil { - return nil, err - } - - err = ch.ExchangeDeclare( - exchange, // name - "topic", // type - true, // durable - false, // auto-deleted - false, // internal - false, // no-wait - nil, // arguments - ) - if err != nil { - return nil, err - } - return ch, err -} - -func Init() { - sec := setting.Cfg.Section("event_publisher") - - if !sec.Key("enabled").MustBool(false) { - return - } - - url = sec.Key("rabbitmq_url").String() - exchange = sec.Key("exchange").String() - bus.AddWildcardListener(eventListener) - - if err := Setup(); err != nil { - log.Fatal(4, "Failed to connect to notification queue: %v", err) - return - } -} - -// Every connection should declare the topology they expect -func Setup() error { - c, err := getConnection() - if err != nil { - return err - } - conn = c - ch, err := getChannel() - if err != nil { - return err - } - - channel = ch - - // listen for close events so we can reconnect. - errChan := channel.NotifyClose(make(chan *amqp.Error)) - go func() { - for e := range errChan { - fmt.Println("connection to rabbitmq lost.") - fmt.Println(e) - fmt.Println("attempting to create new rabbitmq channel.") - ch, err := getChannel() - if err == nil { - channel = ch - break - } - - //could not create channel, so lets close the connection - // and re-create. - _ = conn.Close() - - for err != nil { - time.Sleep(2 * time.Second) - fmt.Println("attempting to reconnect to rabbitmq.") - err = Setup() - } - fmt.Println("Connected to rabbitmq again.") - } - }() - - return nil -} - -func publish(routingKey string, msgString []byte) { - for { - err := channel.Publish( - exchange, //exchange - routingKey, // routing key - false, // mandatory - false, // immediate - amqp.Publishing{ - ContentType: "application/json", - Body: msgString, - }, - ) - if err == nil { - return - } - // failures are most likely because the connection was lost. - // the connection will be re-established, so just keep - // retrying every 2seconds until we successfully publish. - time.Sleep(2 * time.Second) - fmt.Println("publish failed, retrying.") - } -} - -func eventListener(event interface{}) error { - wireEvent, err := events.ToOnWriteEvent(event) - if err != nil { - return err - } - - msgString, err := json.Marshal(wireEvent) - if err != nil { - return err - } - - routingKey := fmt.Sprintf("%s.%s", wireEvent.Priority, wireEvent.EventType) - // this is run in a greenthread and we expect that publish will keep - // retrying until the message gets sent. - go publish(routingKey, msgString) - return nil -} diff --git a/vendor/github.com/streadway/amqp/.gitignore b/vendor/github.com/streadway/amqp/.gitignore deleted file mode 100644 index 58b0e8f326f..00000000000 --- a/vendor/github.com/streadway/amqp/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -spec/spec -examples/simple-consumer/simple-consumer -examples/simple-producer/simple-producer diff --git a/vendor/github.com/streadway/amqp/.travis.yml b/vendor/github.com/streadway/amqp/.travis.yml deleted file mode 100644 index f3e3708d4d0..00000000000 --- a/vendor/github.com/streadway/amqp/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: go - -go: - - 1.1 - - tip - -services: - - rabbitmq - -env: - - AMQP_URL=amqp://guest:guest@127.0.0.1:5672/ GOMAXPROCS=2 - -script: go test -tags integration ./... diff --git a/vendor/github.com/streadway/amqp/LICENSE b/vendor/github.com/streadway/amqp/LICENSE deleted file mode 100644 index 243c0ce7c00..00000000000 --- a/vendor/github.com/streadway/amqp/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/streadway/amqp/README.md b/vendor/github.com/streadway/amqp/README.md deleted file mode 100644 index 4949ac99218..00000000000 --- a/vendor/github.com/streadway/amqp/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# AMQP - -AMQP 0.9.1 client with RabbitMQ extensions in Go. - -# Status - -*Beta* - -[![Build Status](https://secure.travis-ci.org/streadway/amqp.png)](http://travis-ci.org/streadway/amqp) - -API changes unlikely and will be discussed on [Github -issues](https://github.com/streadway/amqp/issues) along with any bugs or -enhancements. - -# Goals - -Provide an functional interface that closely represents the AMQP 0.9.1 model -targeted to RabbitMQ as a server. This includes the minimum necessary to -interact the semantics of the protocol. - -# Non-goals - -Things not intended to be supported. - - * Auto reconnect and re-synchronization of client and server topologies. - * Reconnection would require understanding the error paths when the - topology cannot be declared on reconnect. This would require a new set - of types and code paths that are best suited at the call-site of this - package. AMQP has a dynamic topology that needs all peers to agree. If - this doesn't happen, the behavior is undefined. Instead of producing a - possible interface with undefined behavior, this package is designed to - be simple for the caller to implement the necessary connection-time - topology declaration so that reconnection is trivial and encapsulated in - the caller's application code. - * AMQP Protocol negotiation for forward or backward compatibility. - * 0.9.1 is stable and widely deployed. Versions 0.10 and 1.0 are divergent - specifications that change the semantics and wire format of the protocol. - We will accept patches for other protocol support but have no plans for - implementation ourselves. - * Anything other than PLAIN and EXTERNAL authentication mechanisms. - * Keeping the mechanisms interface modular makes it possible to extend - outside of this package. If other mechanisms prove to be popular, then - we would accept patches to include them in this pacakge. - -# Usage - -See the 'examples' subdirectory for simple producers and consumers executables. -If you have a use-case in mind which isn't well-represented by the examples, -please file an issue. - -# Documentation - -Use [Godoc documentation](http://godoc.org/github.com/streadway/amqp) for -reference and usage. - -[RabbitMQ tutorials in -Go](https://github.com/rabbitmq/rabbitmq-tutorials/tree/master/go) are also -available. - -# Contributing - -Pull requests are very much welcomed. Create your pull request on a non-master -branch, make sure a test or example is included that covers your change and -your commits represent coherent changes that include a reason for the change. - -To run the integration tests, make sure you have RabbitMQ running on any host, -export the environment variable `AMQP_URL=amqp://host/` and run `go test -tags -integration`. TravisCI will also run the integration tests. - -Thanks to the [community of contributors](https://github.com/streadway/amqp/graphs/contributors). - -# License - -BSD 2 clause - see LICENSE for more details. - - diff --git a/vendor/github.com/streadway/amqp/allocator.go b/vendor/github.com/streadway/amqp/allocator.go deleted file mode 100644 index 92841882620..00000000000 --- a/vendor/github.com/streadway/amqp/allocator.go +++ /dev/null @@ -1,106 +0,0 @@ -package amqp - -import ( - "bytes" - "fmt" - "math/big" -) - -const ( - free = 0 - allocated = 1 -) - -// allocator maintains a bitset of allocated numbers. -type allocator struct { - pool *big.Int - last int - low int - high int -} - -// NewAllocator reserves and frees integers out of a range between low and -// high. -// -// O(N) worst case space used, where N is maximum allocated, divided by -// sizeof(big.Word) -func newAllocator(low, high int) *allocator { - return &allocator{ - pool: big.NewInt(0), - last: low, - low: low, - high: high, - } -} - -// String returns a string describing the contents of the allocator like -// "allocator[low..high] reserved..until" -// -// O(N) where N is high-low -func (a allocator) String() string { - b := &bytes.Buffer{} - fmt.Fprintf(b, "allocator[%d..%d]", a.low, a.high) - - for low := a.low; low <= a.high; low++ { - high := low - for a.reserved(high) && high <= a.high { - high++ - } - - if high > low+1 { - fmt.Fprintf(b, " %d..%d", low, high-1) - } else if high > low { - fmt.Fprintf(b, " %d", high-1) - } - - low = high - } - return b.String() -} - -// Next reserves and returns the next available number out of the range between -// low and high. If no number is available, false is returned. -// -// O(N) worst case runtime where N is allocated, but usually O(1) due to a -// rolling index into the oldest allocation. -func (a *allocator) next() (int, bool) { - wrapped := a.last - - // Find trailing bit - for ; a.last <= a.high; a.last++ { - if a.reserve(a.last) { - return a.last, true - } - } - - // Find preceeding free'd pool - a.last = a.low - - for ; a.last < wrapped; a.last++ { - if a.reserve(a.last) { - return a.last, true - } - } - - return 0, false -} - -// reserve claims the bit if it is not already claimed, returning true if -// succesfully claimed. -func (a *allocator) reserve(n int) bool { - if a.reserved(n) { - return false - } - a.pool.SetBit(a.pool, n-a.low, allocated) - return true -} - -// reserved returns true if the integer has been allocated -func (a *allocator) reserved(n int) bool { - return a.pool.Bit(n-a.low) == allocated -} - -// release frees the use of the number for another allocation -func (a *allocator) release(n int) { - a.pool.SetBit(a.pool, n-a.low, free) -} diff --git a/vendor/github.com/streadway/amqp/allocator_test.go b/vendor/github.com/streadway/amqp/allocator_test.go deleted file mode 100644 index 2d6fd5dbaf8..00000000000 --- a/vendor/github.com/streadway/amqp/allocator_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package amqp - -import ( - "math/rand" - "testing" -) - -func TestAllocatorFirstShouldBeTheLow(t *testing.T) { - n, ok := newAllocator(1, 2).next() - if !ok { - t.Fatalf("expected to allocate between 1 and 2") - } - - if want, got := 1, n; want != got { - t.Fatalf("expected to first allocation to be 1") - } -} - -func TestAllocatorShouldBeBoundByHigh(t *testing.T) { - a := newAllocator(1, 2) - - if n, ok := a.next(); n != 1 || !ok { - t.Fatalf("expected to allocate between 1 and 2, got %d, %v", n, ok) - } - if n, ok := a.next(); n != 2 || !ok { - t.Fatalf("expected to allocate between 1 and 2, got %d, %v", n, ok) - } - if _, ok := a.next(); ok { - t.Fatalf("expected not to allocate outside of 1 and 2") - } -} - -func TestAllocatorStringShouldIncludeAllocatedRanges(t *testing.T) { - a := newAllocator(1, 10) - a.reserve(1) - a.reserve(2) - a.reserve(3) - a.reserve(5) - a.reserve(6) - a.reserve(8) - a.reserve(10) - - if want, got := "allocator[1..10] 1..3 5..6 8 10", a.String(); want != got { - t.Fatalf("expected String of %q, got %q", want, got) - } -} - -func TestAllocatorShouldReuseReleased(t *testing.T) { - a := newAllocator(1, 2) - - first, _ := a.next() - if want, got := 1, first; want != got { - t.Fatalf("expected allocation to be %d, got: %d", want, got) - } - - second, _ := a.next() - if want, got := 2, second; want != got { - t.Fatalf("expected allocation to be %d, got: %d", want, got) - } - - a.release(first) - - third, _ := a.next() - if want, got := first, third; want != got { - t.Fatalf("expected third allocation to be %d, got: %d", want, got) - } - - _, ok := a.next() - if want, got := false, ok; want != got { - t.Fatalf("expected fourth allocation to saturate the pool") - } -} - -func TestAllocatorReleasesKeepUpWithAllocationsForAllSizes(t *testing.T) { - const runs = 5 - const max = 13 - - for lim := 1; lim < 2<= lim { // fills the allocator - a.release(int(rand.Int63n(int64(lim)))) - } - if _, ok := a.next(); !ok { - t.Fatalf("expected %d runs of random release of size %d not to fail on allocation %d", runs, lim, i) - } - } - } -} diff --git a/vendor/github.com/streadway/amqp/auth.go b/vendor/github.com/streadway/amqp/auth.go deleted file mode 100644 index bff7d7948ba..00000000000 --- a/vendor/github.com/streadway/amqp/auth.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -package amqp - -import ( - "fmt" -) - -// Authentication interface provides a means for different SASL authentication -// mechanisms to be used during connection tuning. -type Authentication interface { - Mechanism() string - Response() string -} - -// PlainAuth is a similar to Basic Auth in HTTP. -type PlainAuth struct { - Username string - Password string -} - -func (me *PlainAuth) Mechanism() string { - return "PLAIN" -} - -func (me *PlainAuth) Response() string { - return fmt.Sprintf("\000%s\000%s", me.Username, me.Password) -} - -// Finds the first mechanism preferred by the client that the server supports. -func pickSASLMechanism(client []Authentication, serverMechanisms []string) (auth Authentication, ok bool) { - for _, auth = range client { - for _, mech := range serverMechanisms { - if auth.Mechanism() == mech { - return auth, true - } - } - } - - return -} diff --git a/vendor/github.com/streadway/amqp/certs.sh b/vendor/github.com/streadway/amqp/certs.sh deleted file mode 100644 index 834f4224270..00000000000 --- a/vendor/github.com/streadway/amqp/certs.sh +++ /dev/null @@ -1,159 +0,0 @@ -#!/bin/sh -# -# Creates the CA, server and client certs to be used by tls_test.go -# http://www.rabbitmq.com/ssl.html -# -# Copy stdout into the const section of tls_test.go or use for RabbitMQ -# -root=$PWD/certs - -if [ -f $root/ca/serial ]; then - echo >&2 "Previous installation found" - echo >&2 "Remove $root/ca and rerun to overwrite" - exit 1 -fi - -mkdir -p $root/ca/private -mkdir -p $root/ca/certs -mkdir -p $root/server -mkdir -p $root/client - -cd $root/ca - -chmod 700 private -touch index.txt -echo 'unique_subject = no' > index.txt.attr -echo '01' > serial -echo >openssl.cnf ' -[ ca ] -default_ca = testca - -[ testca ] -dir = . -certificate = $dir/cacert.pem -database = $dir/index.txt -new_certs_dir = $dir/certs -private_key = $dir/private/cakey.pem -serial = $dir/serial - -default_crl_days = 7 -default_days = 3650 -default_md = sha1 - -policy = testca_policy -x509_extensions = certificate_extensions - -[ testca_policy ] -commonName = supplied -stateOrProvinceName = optional -countryName = optional -emailAddress = optional -organizationName = optional -organizationalUnitName = optional - -[ certificate_extensions ] -basicConstraints = CA:false - -[ req ] -default_bits = 2048 -default_keyfile = ./private/cakey.pem -default_md = sha1 -prompt = yes -distinguished_name = root_ca_distinguished_name -x509_extensions = root_ca_extensions - -[ root_ca_distinguished_name ] -commonName = hostname - -[ root_ca_extensions ] -basicConstraints = CA:true -keyUsage = keyCertSign, cRLSign - -[ client_ca_extensions ] -basicConstraints = CA:false -keyUsage = digitalSignature -extendedKeyUsage = 1.3.6.1.5.5.7.3.2 - -[ server_ca_extensions ] -basicConstraints = CA:false -keyUsage = keyEncipherment -extendedKeyUsage = 1.3.6.1.5.5.7.3.1 -subjectAltName = @alt_names - -[ alt_names ] -IP.1 = 127.0.0.1 -' - -openssl req \ - -x509 \ - -nodes \ - -config openssl.cnf \ - -newkey rsa:2048 \ - -days 3650 \ - -subj "/CN=MyTestCA/" \ - -out cacert.pem \ - -outform PEM - -openssl x509 \ - -in cacert.pem \ - -out cacert.cer \ - -outform DER - -openssl genrsa -out $root/server/key.pem 2048 -openssl genrsa -out $root/client/key.pem 2048 - -openssl req \ - -new \ - -nodes \ - -config openssl.cnf \ - -subj "/CN=127.0.0.1/O=server/" \ - -key $root/server/key.pem \ - -out $root/server/req.pem \ - -outform PEM - -openssl req \ - -new \ - -nodes \ - -config openssl.cnf \ - -subj "/CN=127.0.0.1/O=client/" \ - -key $root/client/key.pem \ - -out $root/client/req.pem \ - -outform PEM - -openssl ca \ - -config openssl.cnf \ - -in $root/server/req.pem \ - -out $root/server/cert.pem \ - -notext \ - -batch \ - -extensions server_ca_extensions - -openssl ca \ - -config openssl.cnf \ - -in $root/client/req.pem \ - -out $root/client/cert.pem \ - -notext \ - -batch \ - -extensions client_ca_extensions - -cat <<-END -const caCert = \` -`cat $root/ca/cacert.pem` -\` - -const serverCert = \` -`cat $root/server/cert.pem` -\` - -const serverKey = \` -`cat $root/server/key.pem` -\` - -const clientCert = \` -`cat $root/client/cert.pem` -\` - -const clientKey = \` -`cat $root/client/key.pem` -\` -END diff --git a/vendor/github.com/streadway/amqp/channel.go b/vendor/github.com/streadway/amqp/channel.go deleted file mode 100644 index f8710c6c706..00000000000 --- a/vendor/github.com/streadway/amqp/channel.go +++ /dev/null @@ -1,1589 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -package amqp - -import ( - "container/heap" - "reflect" - "sync" -) - -// 0 1 3 7 size+7 size+8 -// +------+---------+-------------+ +------------+ +-----------+ -// | type | channel | size | | payload | | frame-end | -// +------+---------+-------------+ +------------+ +-----------+ -// octet short long size octets octet -const frameHeaderSize = 1 + 2 + 4 + 1 - -/* -Channel represents an AMQP channel. Used as a context for valid message -exchange. Errors on methods with this Channel as a receiver means this channel -should be discarded and a new channel established. - -*/ -type Channel struct { - destructor sync.Once - sendM sync.Mutex // sequence channel frames - m sync.Mutex // struct field mutex - - connection *Connection - - rpc chan message - consumers *consumers - - id uint16 - - // true when we will never notify again - noNotify bool - - // Channel and Connection exceptions will be broadcast on these listeners. - closes []chan *Error - - // Listeners for active=true flow control. When true is sent to a listener, - // publishing should pause until false is sent to listeners. - flows []chan bool - - // Listeners for returned publishings for unroutable messages on mandatory - // publishings or undeliverable messages on immediate publishings. - returns []chan Return - - // Listeners for when the server notifies the client that - // a consumer has been cancelled. - cancels []chan string - - // Listeners for Acks/Nacks when the channel is in Confirm mode - // the value is the sequentially increasing delivery tag - // starting at 1 immediately after the Confirm - acks []chan uint64 - nacks []chan uint64 - - // When in confirm mode, track publish counter and order confirms - confirms tagSet - publishCounter uint64 - - // Selects on any errors from shutdown during RPC - errors chan *Error - - // State machine that manages frame order, must only be mutated by the connection - recv func(*Channel, frame) error - - // State that manages the send behavior after before and after shutdown, must - // only be mutated in shutdown() - send func(*Channel, message) error - - // Current state for frame re-assembly, only mutated from recv - message messageWithContent - header *headerFrame - body []byte -} - -// Constructs a new channel with the given framing rules -func newChannel(c *Connection, id uint16) *Channel { - return &Channel{ - connection: c, - id: id, - rpc: make(chan message), - consumers: makeConsumers(), - recv: (*Channel).recvMethod, - send: (*Channel).sendOpen, - errors: make(chan *Error, 1), - } -} - -// shutdown is called by Connection after the channel has been removed from the -// connection registry. -func (me *Channel) shutdown(e *Error) { - me.destructor.Do(func() { - me.m.Lock() - defer me.m.Unlock() - - // Broadcast abnormal shutdown - if e != nil { - for _, c := range me.closes { - c <- e - } - } - - me.send = (*Channel).sendClosed - - // Notify RPC if we're selecting - if e != nil { - me.errors <- e - } - - me.consumers.closeAll() - - for _, c := range me.closes { - close(c) - } - - for _, c := range me.flows { - close(c) - } - - for _, c := range me.returns { - close(c) - } - - for _, c := range me.cancels { - close(c) - } - - // A seen map to keep from double closing the ack and nacks. the other - // channels are different types and are not shared - seen := make(map[chan uint64]bool) - - for _, c := range me.acks { - if !seen[c] { - close(c) - seen[c] = true - } - } - - for _, c := range me.nacks { - if !seen[c] { - close(c) - seen[c] = true - } - } - - me.noNotify = true - }) -} - -func (me *Channel) open() error { - return me.call(&channelOpen{}, &channelOpenOk{}) -} - -// Performs a request/response call for when the message is not NoWait and is -// specified as Synchronous. -func (me *Channel) call(req message, res ...message) error { - if err := me.send(me, req); err != nil { - return err - } - - if req.wait() { - select { - case e := <-me.errors: - return e - - case msg := <-me.rpc: - if msg != nil { - for _, try := range res { - if reflect.TypeOf(msg) == reflect.TypeOf(try) { - // *res = *msg - vres := reflect.ValueOf(try).Elem() - vmsg := reflect.ValueOf(msg).Elem() - vres.Set(vmsg) - return nil - } - } - return ErrCommandInvalid - } else { - // RPC channel has been closed without an error, likely due to a hard - // error on the Connection. This indicates we have already been - // shutdown and if were waiting, will have returned from the errors chan. - return ErrClosed - } - } - } - - return nil -} - -func (me *Channel) sendClosed(msg message) (err error) { - me.sendM.Lock() - defer me.sendM.Unlock() - - // After a 'channel.close' is sent or received the only valid response is - // channel.close-ok - if _, ok := msg.(*channelCloseOk); ok { - return me.connection.send(&methodFrame{ - ChannelId: me.id, - Method: msg, - }) - } - - return ErrClosed -} - -func (me *Channel) sendOpen(msg message) (err error) { - me.sendM.Lock() - defer me.sendM.Unlock() - - if content, ok := msg.(messageWithContent); ok { - props, body := content.getContent() - class, _ := content.id() - size := me.connection.Config.FrameSize - frameHeaderSize - - if err = me.connection.send(&methodFrame{ - ChannelId: me.id, - Method: content, - }); err != nil { - return - } - - if err = me.connection.send(&headerFrame{ - ChannelId: me.id, - ClassId: class, - Size: uint64(len(body)), - Properties: props, - }); err != nil { - return - } - - for i, j := 0, size; i < len(body); i, j = j, j+size { - if j > len(body) { - j = len(body) - } - - if err = me.connection.send(&bodyFrame{ - ChannelId: me.id, - Body: body[i:j], - }); err != nil { - return - } - } - } else { - err = me.connection.send(&methodFrame{ - ChannelId: me.id, - Method: msg, - }) - } - - return -} - -// Eventually called via the state machine from the connection's reader -// goroutine, so assumes serialized access. -func (me *Channel) dispatch(msg message) { - switch m := msg.(type) { - case *channelClose: - me.connection.closeChannel(me, newError(m.ReplyCode, m.ReplyText)) - me.send(me, &channelCloseOk{}) - - case *channelFlow: - for _, c := range me.flows { - c <- m.Active - } - me.send(me, &channelFlowOk{Active: m.Active}) - - case *basicCancel: - for _, c := range me.cancels { - c <- m.ConsumerTag - } - me.send(me, &basicCancelOk{ConsumerTag: m.ConsumerTag}) - - case *basicReturn: - ret := newReturn(*m) - for _, c := range me.returns { - c <- *ret - } - - case *basicAck: - if m.Multiple { - me.confimMultiple(m.DeliveryTag, me.acks) - } else { - me.confimOne(m.DeliveryTag, me.acks) - } - - case *basicNack: - if m.Multiple { - me.confimMultiple(m.DeliveryTag, me.nacks) - } else { - me.confimOne(m.DeliveryTag, me.nacks) - } - - case *basicDeliver: - me.consumers.send(m.ConsumerTag, newDelivery(me, m)) - // TODO log failed consumer and close channel, this can happen when - // deliveries are in flight and a no-wait cancel has happened - - default: - me.rpc <- msg - } -} - -func (me *Channel) transition(f func(*Channel, frame) error) error { - me.recv = f - return nil -} - -func (me *Channel) recvMethod(f frame) error { - switch frame := f.(type) { - case *methodFrame: - if msg, ok := frame.Method.(messageWithContent); ok { - me.body = make([]byte, 0) - me.message = msg - return me.transition((*Channel).recvHeader) - } - - me.dispatch(frame.Method) // termination state - return me.transition((*Channel).recvMethod) - - case *headerFrame: - // drop - return me.transition((*Channel).recvMethod) - - case *bodyFrame: - // drop - return me.transition((*Channel).recvMethod) - - default: - panic("unexpected frame type") - } - - panic("unreachable") -} - -func (me *Channel) recvHeader(f frame) error { - switch frame := f.(type) { - case *methodFrame: - // interrupt content and handle method - return me.recvMethod(f) - - case *headerFrame: - // start collecting if we expect body frames - me.header = frame - - if frame.Size == 0 { - me.message.setContent(me.header.Properties, me.body) - me.dispatch(me.message) // termination state - return me.transition((*Channel).recvMethod) - } else { - return me.transition((*Channel).recvContent) - } - - case *bodyFrame: - // drop and reset - return me.transition((*Channel).recvMethod) - - default: - panic("unexpected frame type") - } - - panic("unreachable") -} - -// state after method + header and before the length -// defined by the header has been reached -func (me *Channel) recvContent(f frame) error { - switch frame := f.(type) { - case *methodFrame: - // interrupt content and handle method - return me.recvMethod(f) - - case *headerFrame: - // drop and reset - return me.transition((*Channel).recvMethod) - - case *bodyFrame: - me.body = append(me.body, frame.Body...) - - if uint64(len(me.body)) >= me.header.Size { - me.message.setContent(me.header.Properties, me.body) - me.dispatch(me.message) // termination state - return me.transition((*Channel).recvMethod) - } - - return me.transition((*Channel).recvContent) - - default: - panic("unexpected frame type") - } - - panic("unreachable") -} - -/* -Close initiate a clean channel closure by sending a close message with the error -code set to '200'. - -It is safe to call this method multiple times. - -*/ -func (me *Channel) Close() error { - defer me.connection.closeChannel(me, nil) - return me.call( - &channelClose{ReplyCode: replySuccess}, - &channelCloseOk{}, - ) -} - -/* -NotifyClose registers a listener for when the server sends a channel or -connection exception in the form of a Connection.Close or Channel.Close method. -Connection exceptions will be broadcast to all open channels and all channels -will be closed, where channel exceptions will only be broadcast to listeners to -this channel. - -The chan provided will be closed when the Channel is closed and on a -graceful close, no error will be sent. - -*/ -func (me *Channel) NotifyClose(c chan *Error) chan *Error { - me.m.Lock() - defer me.m.Unlock() - - if me.noNotify { - close(c) - } else { - me.closes = append(me.closes, c) - } - - return c -} - -/* -NotifyFlow registers a listener for basic.flow methods sent by the server. -When `true` is sent on one of the listener channels, all publishers should -pause until a `false` is sent. - -The server may ask the producer to pause or restart the flow of Publishings -sent by on a channel. This is a simple flow-control mechanism that a server can -use to avoid overflowing its queues or otherwise finding itself receiving more -messages than it can process. Note that this method is not intended for window -control. It does not affect contents returned by basic.get-ok methods. - -When a new channel is opened, it is active (flow is active). Some -applications assume that channels are inactive until started. To emulate -this behavior a client MAY open the channel, then pause it. - -Publishers should respond to a flow messages as rapidly as possible and the -server may disconnect over producing channels that do not respect these -messages. - -basic.flow-ok methods will always be returned to the server regardless of -the number of listeners there are. - -To control the flow of deliveries from the server. Use the Channel.Flow() -method instead. - -Note: RabbitMQ will rather use TCP pushback on the network connection instead -of sending basic.flow. This means that if a single channel is producing too -much on the same connection, all channels using that connection will suffer, -including acknowledgments from deliveries. Use different Connections if you -desire to interleave consumers and producers in the same process to avoid your -basic.ack messages from getting rate limited with your basic.publish messages. - -*/ -func (me *Channel) NotifyFlow(c chan bool) chan bool { - me.m.Lock() - defer me.m.Unlock() - - if me.noNotify { - close(c) - } else { - me.flows = append(me.flows, c) - } - - return c -} - -/* -NotifyReturn registers a listener for basic.return methods. These can be sent -from the server when a publish is undeliverable either from the mandatory or -immediate flags. - -A return struct has a copy of the Publishing along with some error -information about why the publishing failed. - -*/ -func (me *Channel) NotifyReturn(c chan Return) chan Return { - me.m.Lock() - defer me.m.Unlock() - - if me.noNotify { - close(c) - } else { - me.returns = append(me.returns, c) - } - - return c -} - -/* -NotifyCancel registers a listener for basic.cancel methods. These can be sent -from the server when a queue is deleted or when consuming from a mirrored queue -where the master has just failed (and was moved to another node) - -The subscription tag is returned to the listener. - -*/ -func (me *Channel) NotifyCancel(c chan string) chan string { - me.m.Lock() - defer me.m.Unlock() - - if me.noNotify { - close(c) - } else { - me.cancels = append(me.cancels, c) - } - - return c -} - -/* -NotifyConfirm registers a listener chan for reliable publishing to receive -basic.ack and basic.nack messages. These messages will be sent by the server -for every publish after Channel.Confirm has been called. The value sent on -these channels is the sequence number of the publishing. It is up to client of -this channel to maintain the sequence number of each publishing and handle -resends on basic.nack. - -There will be either at most one Ack or Nack delivered for every Publishing. - -Acknowledgments will be received in the order of delivery from the -NotifyConfirm channels even if the server acknowledges them out of order. - -The capacity of the ack and nack channels must be at least as large as the -number of outstanding publishings. Not having enough buffered chans will -create a deadlock if you attempt to perform other operations on the Connection -or Channel while confirms are in-flight. - -It's advisable to wait for all acks or nacks to arrive before calling -Channel.Close(). - -*/ -func (me *Channel) NotifyConfirm(ack, nack chan uint64) (chan uint64, chan uint64) { - me.m.Lock() - defer me.m.Unlock() - - if me.noNotify { - close(ack) - close(nack) - } else { - me.acks = append(me.acks, ack) - me.nacks = append(me.nacks, nack) - } - - return ack, nack -} - -// Since the acknowledgments may come out of order, scan the heap -// until found. In most cases, only the head will be found. -func (me *Channel) confimOne(tag uint64, ch []chan uint64) { - me.m.Lock() - defer me.m.Unlock() - - if me.confirms != nil { - var unacked []uint64 - - for { - // We expect once and only once delivery - next := heap.Pop(&me.confirms).(uint64) - - if next != tag { - unacked = append(unacked, next) - } else { - for _, c := range ch { - c <- tag - } - break - } - } - - for _, pending := range unacked { - heap.Push(&me.confirms, pending) - } - } -} - -// Instead of pushing the pending acknowledgments, deliver them as we should ack -// all up until this tag. -func (me *Channel) confimMultiple(tag uint64, ch []chan uint64) { - me.m.Lock() - defer me.m.Unlock() - - if me.confirms != nil { - for { - // We expect once and only once delivery - next := heap.Pop(&me.confirms).(uint64) - - for _, c := range ch { - c <- next - } - - if next == tag { - break - } - } - } -} - -/* -Qos controls how many messages or how many bytes the server will try to keep on -the network for consumers before receiving delivery acks. The intent of Qos is -to make sure the network buffers stay full between the server and client. - -With a prefetch count greater than zero, the server will deliver that many -messages to consumers before acknowledgments are received. The server ignores -this option when consumers are started with noAck because no acknowledgments -are expected or sent. - -With a prefetch size greater than zero, the server will try to keep at least -that many bytes of deliveries flushed to the network before receiving -acknowledgments from the consumers. This option is ignored when consumers are -started with noAck. - -When global is true, these Qos settings apply to all existing and future -consumers on all channels on the same connection. When false, the Channel.Qos -settings will apply to all existing and future consumers on this channel. -RabbitMQ does not implement the global flag. - -To get round-robin behavior between consumers consuming from the same queue on -different connections, set the prefetch count to 1, and the next available -message on the server will be delivered to the next available consumer. - -If your consumer work time is reasonably is consistent and not much greater -than two times your network round trip time, you will see significant -throughput improvements starting with a prefetch count of 2 or slightly -greater as described by benchmarks on RabbitMQ. - -http://www.rabbitmq.com/blog/2012/04/25/rabbitmq-performance-measurements-part-2/ -*/ -func (me *Channel) Qos(prefetchCount, prefetchSize int, global bool) error { - return me.call( - &basicQos{ - PrefetchCount: uint16(prefetchCount), - PrefetchSize: uint32(prefetchSize), - Global: global, - }, - &basicQosOk{}, - ) -} - -/* -Cancel stops deliveries to the consumer chan established in Channel.Consume and -identified by consumer. - -Only use this method to cleanly stop receiving deliveries from the server and -cleanly shut down the consumer chan identified by this tag. Using this method -and waiting for remaining messages to flush from the consumer chan will ensure -all messages received on the network will be delivered to the receiver of your -consumer chan. - -Continue consuming from the chan Delivery provided by Channel.Consume until the -chan closes. - -When noWait is true, do not wait for the server to acknowledge the cancel. -Only use this when you are certain there are no deliveries requiring -acknowledgment are in-flight otherwise they will arrive and be dropped in the -client without an ack and will not be redelivered to other consumers. - -*/ -func (me *Channel) Cancel(consumer string, noWait bool) error { - req := &basicCancel{ - ConsumerTag: consumer, - NoWait: noWait, - } - res := &basicCancelOk{} - - if err := me.call(req, res); err != nil { - return err - } - - if req.wait() { - me.consumers.close(res.ConsumerTag) - } else { - // Potentially could drop deliveries in flight - me.consumers.close(consumer) - } - - return nil -} - -/* -QueueDeclare declares a queue to hold messages and deliver to consumers. -Declaring creates a queue if it doesn't already exist, or ensures that an -existing queue matches the same parameters. - -Every queue declared gets a default binding to the empty exchange "" which has -the type "direct" with the routing key matching the queue's name. With this -default binding, it is possible to publish messages that route directly to -this queue by publishing to "" with the routing key of the queue name. - - QueueDeclare("alerts", true, false, false false, false, nil) - Publish("", "alerts", false, false, Publishing{Body: []byte("...")}) - - Delivery Exchange Key Queue - ----------------------------------------------- - key: alerts -> "" -> alerts -> alerts - -The queue name may be empty, in which the server will generate a unique name -which will be returned in the Name field of Queue struct. - -Durable and Non-Auto-Deleted queues will survive server restarts and remain -when there are no remaining consumers or bindings. Persistent publishings will -be restored in this queue on server restart. These queues are only able to be -bound to durable exchanges. - -Non-Durable and Auto-Deleted queues will not be redeclared on server restart -and will be deleted by the server after a short time when the last consumer is -canceled or the last consumer's channel is closed. Queues with this lifetime -can also be deleted normally with QueueDelete. These durable queues can only -be bound to non-durable exchanges. - -Non-Durable and Non-Auto-Deleted queues will remain declared as long as the -server is running regardless of how many consumers. This lifetime is useful -for temporary topologies that may have long delays between consumer activity. -These queues can only be bound to non-durable exchanges. - -Durable and Auto-Deleted queues will be restored on server restart, but without -active consumers, will not survive and be removed. This Lifetime is unlikely -to be useful. - -Exclusive queues are only accessible by the connection that declares them and -will be deleted when the connection closes. Channels on other connections -will receive an error when attempting declare, bind, consume, purge or delete a -queue with the same name. - -When noWait is true, the queue will assume to be declared on the server. A -channel exception will arrive if the conditions are met for existing queues -or attempting to modify an existing queue from a different connection. - -When the error return value is not nil, you can assume the queue could not be -declared with these parameters and the channel will be closed. - -*/ -func (me *Channel) QueueDeclare(name string, durable, autoDelete, exclusive, noWait bool, args Table) (Queue, error) { - if err := args.Validate(); err != nil { - return Queue{}, err - } - - req := &queueDeclare{ - Queue: name, - Passive: false, - Durable: durable, - AutoDelete: autoDelete, - Exclusive: exclusive, - NoWait: noWait, - Arguments: args, - } - res := &queueDeclareOk{} - - if err := me.call(req, res); err != nil { - return Queue{}, err - } - - if req.wait() { - return Queue{ - Name: res.Queue, - Messages: int(res.MessageCount), - Consumers: int(res.ConsumerCount), - }, nil - } - - return Queue{ - Name: name, - }, nil - - panic("unreachable") -} - -/* - -QueueDeclarePassive is functionally and parametrically equivalent to -QueueDeclare, except that it sets the "passive" attribute to true. A passive -queue is assumed by RabbitMQ to already exist, and attempting to connect to a -non-existent queue will cause RabbitMQ to throw an exception. This function -can be used to test for the existence of a queue. - -*/ -func (me *Channel) QueueDeclarePassive(name string, durable, autoDelete, exclusive, noWait bool, args Table) (Queue, error) { - if err := args.Validate(); err != nil { - return Queue{}, err - } - - req := &queueDeclare{ - Queue: name, - Passive: true, - Durable: durable, - AutoDelete: autoDelete, - Exclusive: exclusive, - NoWait: noWait, - Arguments: args, - } - res := &queueDeclareOk{} - - if err := me.call(req, res); err != nil { - return Queue{}, err - } - - if req.wait() { - return Queue{ - Name: res.Queue, - Messages: int(res.MessageCount), - Consumers: int(res.ConsumerCount), - }, nil - } - - return Queue{ - Name: name, - }, nil - - panic("unreachable") -} - -/* -QueueInspect passively declares a queue by name to inspect the current message -count, consumer count. - -Use this method to check how many unacknowledged messages reside in the queue -and how many consumers are receiving deliveries and whether a queue by this -name already exists. - -If the queue by this name exists, use Channel.QueueDeclare check if it is -declared with specific parameters. - -If a queue by this name does not exist, an error will be returned and the -channel will be closed. - -*/ -func (me *Channel) QueueInspect(name string) (Queue, error) { - req := &queueDeclare{ - Queue: name, - Passive: true, - } - res := &queueDeclareOk{} - - err := me.call(req, res) - - state := Queue{ - Name: name, - Messages: int(res.MessageCount), - Consumers: int(res.ConsumerCount), - } - - return state, err -} - -/* -QueueBind binds an exchange to a queue so that publishings to the exchange will -be routed to the queue when the publishing routing key matches the binding -routing key. - - QueueBind("pagers", "alert", "log", false, nil) - QueueBind("emails", "info", "log", false, nil) - - Delivery Exchange Key Queue - ----------------------------------------------- - key: alert --> log ----> alert --> pagers - key: info ---> log ----> info ---> emails - key: debug --> log (none) (dropped) - -If a binding with the same key and arguments already exists between the -exchange and queue, the attempt to rebind will be ignored and the existing -binding will be retained. - -In the case that multiple bindings may cause the message to be routed to the -same queue, the server will only route the publishing once. This is possible -with topic exchanges. - - QueueBind("pagers", "alert", "amq.topic", false, nil) - QueueBind("emails", "info", "amq.topic", false, nil) - QueueBind("emails", "#", "amq.topic", false, nil) // match everything - - Delivery Exchange Key Queue - ----------------------------------------------- - key: alert --> amq.topic ----> alert --> pagers - key: info ---> amq.topic ----> # ------> emails - \---> info ---/ - key: debug --> amq.topic ----> # ------> emails - -It is only possible to bind a durable queue to a durable exchange regardless of -whether the queue or exchange is auto-deleted. Bindings between durable queues -and exchanges will also be restored on server restart. - -If the binding could not complete, an error will be returned and the channel -will be closed. - -When noWait is true and the queue could not be bound, the channel will be -closed with an error. - -*/ -func (me *Channel) QueueBind(name, key, exchange string, noWait bool, args Table) error { - if err := args.Validate(); err != nil { - return err - } - - return me.call( - &queueBind{ - Queue: name, - Exchange: exchange, - RoutingKey: key, - NoWait: noWait, - Arguments: args, - }, - &queueBindOk{}, - ) -} - -/* -QueueUnbind removes a binding between an exchange and queue matching the key and -arguments. - -It is possible to send and empty string for the exchange name which means to -unbind the queue from the default exchange. - -*/ -func (me *Channel) QueueUnbind(name, key, exchange string, args Table) error { - if err := args.Validate(); err != nil { - return err - } - - return me.call( - &queueUnbind{ - Queue: name, - Exchange: exchange, - RoutingKey: key, - Arguments: args, - }, - &queueUnbindOk{}, - ) -} - -/* -QueuePurge removes all messages from the named queue which are not waiting to -be acknowledged. Messages that have been delivered but have not yet been -acknowledged will not be removed. - -When successful, returns the number of messages purged. - -If noWait is true, do not wait for the server response and the number of -messages purged will not be meaningful. -*/ -func (me *Channel) QueuePurge(name string, noWait bool) (int, error) { - req := &queuePurge{ - Queue: name, - NoWait: noWait, - } - res := &queuePurgeOk{} - - err := me.call(req, res) - - return int(res.MessageCount), err -} - -/* -QueueDelete removes the queue from the server including all bindings then -purges the messages based on server configuration, returning the number of -messages purged. - -When ifUnused is true, the queue will not be deleted if there are any -consumers on the queue. If there are consumers, an error will be returned and -the channel will be closed. - -When ifEmpty is true, the queue will not be deleted if there are any messages -remaining on the queue. If there are messages, an error will be returned and -the channel will be closed. - -When noWait is true, the queue will be deleted without waiting for a response -from the server. The purged message count will not be meaningful. If the queue -could not be deleted, a channel exception will be raised and the channel will -be closed. - -*/ -func (me *Channel) QueueDelete(name string, ifUnused, ifEmpty, noWait bool) (int, error) { - req := &queueDelete{ - Queue: name, - IfUnused: ifUnused, - IfEmpty: ifEmpty, - NoWait: noWait, - } - res := &queueDeleteOk{} - - err := me.call(req, res) - - return int(res.MessageCount), err -} - -/* -Consume immediately starts delivering queued messages. - -Begin receiving on the returned chan Delivery before any other operation on the -Connection or Channel. - -Continues deliveries to the returned chan Delivery until Channel.Cancel, -Connection.Close, Channel.Close, or an AMQP exception occurs. Consumers must -range over the chan to ensure all deliveries are received. Unreceived -deliveries will block all methods on the same connection. - -All deliveries in AMQP must be acknowledged. It is expected of the consumer to -call Delivery.Ack after it has successfully processed the delivery. If the -consumer is cancelled or the channel or connection is closed any unacknowledged -deliveries will be requeued at the end of the same queue. - -The consumer is identified by a string that is unique and scoped for all -consumers on this channel. If you wish to eventually cancel the consumer, use -the same non-empty idenfitier in Channel.Cancel. An empty string will cause -the library to generate a unique identity. The consumer identity will be -included in every Delivery in the ConsumerTag field - -When autoAck (also known as noAck) is true, the server will acknowledge -deliveries to this consumer prior to writing the delivery to the network. When -autoAck is true, the consumer should not call Delivery.Ack. Automatically -acknowledging deliveries means that some deliveries may get lost if the -consumer is unable to process them after the server delivers them. - -When exclusive is true, the server will ensure that this is the sole consumer -from this queue. When exclusive is false, the server will fairly distribute -deliveries across multiple consumers. - -When noLocal is true, the server will not deliver publishing sent from the same -connection to this consumer. It's advisable to use separate connections for -Channel.Publish and Channel.Consume so not to have TCP pushback on publishing -affect the ability to consume messages, so this parameter is here mostly for -completeness. - -When noWait is true, do not wait for the server to confirm the request and -immediately begin deliveries. If it is not possible to consume, a channel -exception will be raised and the channel will be closed. - -Optional arguments can be provided that have specific semantics for the queue -or server. - -When the channel or connection closes, all delivery chans will also close. - -Deliveries on the returned chan will be buffered indefinitely. To limit memory -of this buffer, use the Channel.Qos method to limit the amount of -unacknowledged/buffered deliveries the server will deliver on this Channel. - -*/ -func (me *Channel) Consume(queue, consumer string, autoAck, exclusive, noLocal, noWait bool, args Table) (<-chan Delivery, error) { - // When we return from me.call, there may be a delivery already for the - // consumer that hasn't been added to the consumer hash yet. Because of - // this, we never rely on the server picking a consumer tag for us. - - if err := args.Validate(); err != nil { - return nil, err - } - - if consumer == "" { - consumer = uniqueConsumerTag() - } - - req := &basicConsume{ - Queue: queue, - ConsumerTag: consumer, - NoLocal: noLocal, - NoAck: autoAck, - Exclusive: exclusive, - NoWait: noWait, - Arguments: args, - } - res := &basicConsumeOk{} - - deliveries := make(chan Delivery) - - me.consumers.add(consumer, deliveries) - - if err := me.call(req, res); err != nil { - me.consumers.close(consumer) - return nil, err - } - - return (<-chan Delivery)(deliveries), nil -} - -/* -ExchangeDeclare declares an exchange on the server. If the exchange does not -already exist, the server will create it. If the exchange exists, the server -verifies that it is of the provided type, durability and auto-delete flags. - -Errors returned from this method will close the channel. - -Exchange names starting with "amq." are reserved for pre-declared and -standardized exchanges. The client MAY declare an exchange starting with -"amq." if the passive option is set, or the exchange already exists. Names can -consists of a non-empty sequence of letters, digits, hyphen, underscore, -period, or colon. - -Each exchange belongs to one of a set of exchange kinds/types implemented by -the server. The exchange types define the functionality of the exchange - i.e. -how messages are routed through it. Once an exchange is declared, its type -cannot be changed. The common types are "direct", "fanout", "topic" and -"headers". - -Durable and Non-Auto-Deleted exchanges will survive server restarts and remain -declared when there are no remaining bindings. This is the best lifetime for -long-lived exchange configurations like stable routes and default exchanges. - -Non-Durable and Auto-Deleted exchanges will be deleted when there are no -remaining bindings and not restored on server restart. This lifetime is -useful for temporary topologies that should not pollute the virtual host on -failure or after the consumers have completed. - -Non-Durable and Non-Auto-deleted exchanges will remain as long as the server is -running including when there are no remaining bindings. This is useful for -temporary topologies that may have long delays between bindings. - -Durable and Auto-Deleted exchanges will survive server restarts and will be -removed before and after server restarts when there are no remaining bindings. -These exchanges are useful for robust temporary topologies or when you require -binding durable queues to auto-deleted exchanges. - -Note: RabbitMQ declares the default exchange types like 'amq.fanout' as -durable, so queues that bind to these pre-declared exchanges must also be -durable. - -Exchanges declared as `internal` do not accept accept publishings. Internal -exchanges are useful for when you wish to implement inter-exchange topologies -that should not be exposed to users of the broker. - -When noWait is true, declare without waiting for a confirmation from the server. -The channel may be closed as a result of an error. Add a NotifyClose listener -to respond to any exceptions. - -Optional amqp.Table of arguments that are specific to the server's implementation of -the exchange can be sent for exchange types that require extra parameters. -*/ -func (me *Channel) ExchangeDeclare(name, kind string, durable, autoDelete, internal, noWait bool, args Table) error { - if err := args.Validate(); err != nil { - return err - } - - return me.call( - &exchangeDeclare{ - Exchange: name, - Type: kind, - Passive: false, - Durable: durable, - AutoDelete: autoDelete, - Internal: internal, - NoWait: noWait, - Arguments: args, - }, - &exchangeDeclareOk{}, - ) -} - -/* - -ExchangeDeclarePassive is functionally and parametrically equivalent to -ExchangeDeclare, except that it sets the "passive" attribute to true. A passive -exchange is assumed by RabbitMQ to already exist, and attempting to connect to a -non-existent exchange will cause RabbitMQ to throw an exception. This function -can be used to detect the existence of an exchange. - -*/ -func (me *Channel) ExchangeDeclarePassive(name, kind string, durable, autoDelete, internal, noWait bool, args Table) error { - if err := args.Validate(); err != nil { - return err - } - - return me.call( - &exchangeDeclare{ - Exchange: name, - Type: kind, - Passive: true, - Durable: durable, - AutoDelete: autoDelete, - Internal: internal, - NoWait: noWait, - Arguments: args, - }, - &exchangeDeclareOk{}, - ) -} - -/* -ExchangeDelete removes the named exchange from the server. When an exchange is -deleted all queue bindings on the exchange are also deleted. If this exchange -does not exist, the channel will be closed with an error. - -When ifUnused is true, the server will only delete the exchange if it has no queue -bindings. If the exchange has queue bindings the server does not delete it -but close the channel with an exception instead. Set this to true if you are -not the sole owner of the exchange. - -When noWait is true, do not wait for a server confirmation that the exchange has -been deleted. Failing to delete the channel could close the channel. Add a -NotifyClose listener to respond to these channel exceptions. -*/ -func (me *Channel) ExchangeDelete(name string, ifUnused, noWait bool) error { - return me.call( - &exchangeDelete{ - Exchange: name, - IfUnused: ifUnused, - NoWait: noWait, - }, - &exchangeDeleteOk{}, - ) -} - -/* -ExchangeBind binds an exchange to another exchange to create inter-exchange -routing topologies on the server. This can decouple the private topology and -routing exchanges from exchanges intended solely for publishing endpoints. - -Binding two exchanges with identical arguments will not create duplicate -bindings. - -Binding one exchange to another with multiple bindings will only deliver a -message once. For example if you bind your exchange to `amq.fanout` with two -different binding keys, only a single message will be delivered to your -exchange even though multiple bindings will match. - -Given a message delivered to the source exchange, the message will be forwarded -to the destination exchange when the routing key is matched. - - ExchangeBind("sell", "MSFT", "trade", false, nil) - ExchangeBind("buy", "AAPL", "trade", false, nil) - - Delivery Source Key Destination - example exchange exchange - ----------------------------------------------- - key: AAPL --> trade ----> MSFT sell - \---> AAPL --> buy - -When noWait is true, do not wait for the server to confirm the binding. If any -error occurs the channel will be closed. Add a listener to NotifyClose to -handle these errors. - -Optional arguments specific to the exchanges bound can also be specified. -*/ -func (me *Channel) ExchangeBind(destination, key, source string, noWait bool, args Table) error { - if err := args.Validate(); err != nil { - return err - } - - return me.call( - &exchangeBind{ - Destination: destination, - Source: source, - RoutingKey: key, - NoWait: noWait, - Arguments: args, - }, - &exchangeBindOk{}, - ) -} - -/* -ExchangeUnbind unbinds the destination exchange from the source exchange on the -server by removing the routing key between them. This is the inverse of -ExchangeBind. If the binding does not currently exist, an error will be -returned. - -When noWait is true, do not wait for the server to confirm the deletion of the -binding. If any error occurs the channel will be closed. Add a listener to -NotifyClose to handle these errors. - -Optional arguments that are specific to the type of exchanges bound can also be -provided. These must match the same arguments specified in ExchangeBind to -identify the binding. -*/ -func (me *Channel) ExchangeUnbind(destination, key, source string, noWait bool, args Table) error { - if err := args.Validate(); err != nil { - return err - } - - return me.call( - &exchangeUnbind{ - Destination: destination, - Source: source, - RoutingKey: key, - NoWait: noWait, - Arguments: args, - }, - &exchangeUnbindOk{}, - ) -} - -/* -Publish sends a Publishing from the client to an exchange on the server. - -When you want a single message to be delivered to a single queue, you can -publish to the default exchange with the routingKey of the queue name. This is -because every declared queue gets an implicit route to the default exchange. - -Since publishings are asynchronous, any undeliverable message will get returned -by the server. Add a listener with Channel.NotifyReturn to handle any -undeliverable message when calling publish with either the mandatory or -immediate parameters as true. - -Publishings can be undeliverable when the mandatory flag is true and no queue is -bound that matches the routing key, or when the immediate flag is true and no -consumer on the matched queue is ready to accept the delivery. - -This can return an error when the channel, connection or socket is closed. The -error or lack of an error does not indicate whether the server has received this -publishing. - -It is possible for publishing to not reach the broker if the underlying socket -is shutdown without pending publishing packets being flushed from the kernel -buffers. The easy way of making it probable that all publishings reach the -server is to always call Connection.Close before terminating your publishing -application. The way to ensure that all publishings reach the server is to add -a listener to Channel.NotifyConfirm and keep track of the server acks and nacks -for every publishing you publish, only exiting when all publishings are -accounted for. - -*/ -func (me *Channel) Publish(exchange, key string, mandatory, immediate bool, msg Publishing) error { - if err := msg.Headers.Validate(); err != nil { - return err - } - - me.m.Lock() - defer me.m.Unlock() - - if err := me.send(me, &basicPublish{ - Exchange: exchange, - RoutingKey: key, - Mandatory: mandatory, - Immediate: immediate, - Body: msg.Body, - Properties: properties{ - Headers: msg.Headers, - ContentType: msg.ContentType, - ContentEncoding: msg.ContentEncoding, - DeliveryMode: msg.DeliveryMode, - Priority: msg.Priority, - CorrelationId: msg.CorrelationId, - ReplyTo: msg.ReplyTo, - Expiration: msg.Expiration, - MessageId: msg.MessageId, - Timestamp: msg.Timestamp, - Type: msg.Type, - UserId: msg.UserId, - AppId: msg.AppId, - }, - }); err != nil { - return err - } - - me.publishCounter += 1 - - if me.confirms != nil { - heap.Push(&me.confirms, me.publishCounter) - } - - return nil -} - -/* -Get synchronously receives a single Delivery from the head of a queue from the -server to the client. In almost all cases, using Channel.Consume will be -preferred. - -If there was a delivery waiting on the queue and that delivery was received the -second return value will be true. If there was no delivery waiting or an error -occured, the ok bool will be false. - -All deliveries must be acknowledged including those from Channel.Get. Call -Delivery.Ack on the returned delivery when you have fully processed this -delivery. - -When autoAck is true, the server will automatically acknowledge this message so -you don't have to. But if you are unable to fully process this message before -the channel or connection is closed, the message will not get requeued. - -*/ -func (me *Channel) Get(queue string, autoAck bool) (msg Delivery, ok bool, err error) { - req := &basicGet{Queue: queue, NoAck: autoAck} - res := &basicGetOk{} - empty := &basicGetEmpty{} - - if err := me.call(req, res, empty); err != nil { - return Delivery{}, false, err - } - - if res.DeliveryTag > 0 { - return *(newDelivery(me, res)), true, nil - } - - return Delivery{}, false, nil -} - -/* -Tx puts the channel into transaction mode on the server. All publishings and -acknowledgments following this method will be atomically committed or rolled -back for a single queue. Call either Channel.TxCommit or Channel.TxRollback to -leave a this transaction and immediately start a new transaction. - -The atomicity across multiple queues is not defined as queue declarations and -bindings are not included in the transaction. - -The behavior of publishings that are delivered as mandatory or immediate while -the channel is in a transaction is not defined. - -Once a channel has been put into transaction mode, it cannot be taken out of -transaction mode. Use a different channel for non-transactional semantics. - -*/ -func (me *Channel) Tx() error { - return me.call( - &txSelect{}, - &txSelectOk{}, - ) -} - -/* -TxCommit atomically commits all publishings and acknowledgments for a single -queue and immediately start a new transaction. - -Calling this method without having called Channel.Tx is an error. - -*/ -func (me *Channel) TxCommit() error { - return me.call( - &txCommit{}, - &txCommitOk{}, - ) -} - -/* -TxRollback atomically rolls back all publishings and acknowledgments for a -single queue and immediately start a new transaction. - -Calling this method without having called Channel.Tx is an error. - -*/ -func (me *Channel) TxRollback() error { - return me.call( - &txRollback{}, - &txRollbackOk{}, - ) -} - -/* -Flow pauses the delivery of messages to consumers on this channel. Channels -are opened with flow control not active, to open a channel with paused -deliveries immediately call this method with true after calling -Connection.Channel. - -When active is true, this method asks the server to temporarily pause deliveries -until called again with active as false. - -Channel.Get methods will not be affected by flow control. - -This method is not intended to act as window control. Use Channel.Qos to limit -the number of unacknowledged messages or bytes in flight instead. - -The server may also send us flow methods to throttle our publishings. A well -behaving publishing client should add a listener with Channel.NotifyFlow and -pause its publishings when true is sent on that channel. - -Note: RabbitMQ prefers to use TCP push back to control flow for all channels on -a connection, so under high volume scenarios, it's wise to open separate -Connections for publishings and deliveries. - -*/ -func (me *Channel) Flow(active bool) error { - return me.call( - &channelFlow{Active: active}, - &channelFlowOk{}, - ) -} - -/* -Confirm puts this channel into confirm mode so that the client can ensure all -publishings have successfully been received by the server. After entering this -mode, the server will send a basic.ack or basic.nack message with the deliver -tag set to a 1 based incrementing index corresponding to every publishing -received after the this method returns. - -Add a listener to Channel.NotifyConfirm to respond to the acknowledgments and -negative acknowledgments before publishing. If Channel.NotifyConfirm is not -called, the Ack/Nacks will be silently ignored. - -The order of acknowledgments is not bound to the order of deliveries. - -Ack and Nack confirmations will arrive at some point in the future. - -Unroutable mandatory or immediate messages are acknowledged immediately after -any Channel.NotifyReturn listeners have been notified. Other messages are -acknowledged when all queues that should have the message routed to them have -either have received acknowledgment of delivery or have enqueued the message, -persisting the message if necessary. - -When noWait is true, the client will not wait for a response. A channel -exception could occur if the server does not support this method. - -*/ -func (me *Channel) Confirm(noWait bool) error { - me.m.Lock() - defer me.m.Unlock() - - if err := me.call( - &confirmSelect{Nowait: noWait}, - &confirmSelectOk{}, - ); err != nil { - return err - } - - // Indicates we're in confirm mode - me.confirms = make(tagSet, 0) - - return nil -} - -/* -Recover redelivers all unacknowledged deliveries on this channel. - -When requeue is false, messages will be redelivered to the original consumer. - -When requeue is true, messages will be redelivered to any available consumer, -potentially including the original. - -If the deliveries cannot be recovered, an error will be returned and the channel -will be closed. - -Note: this method is not implemented on RabbitMQ, use Delivery.Nack instead -*/ -func (me *Channel) Recover(requeue bool) error { - return me.call( - &basicRecover{Requeue: requeue}, - &basicRecoverOk{}, - ) -} - -/* -Ack acknowledges a delivery by its delivery tag when having been consumed with -Channel.Consume or Channel.Get. - -Ack acknowledges all message received prior to the delivery tag when multiple -is true. - -See also Delivery.Ack -*/ -func (me *Channel) Ack(tag uint64, multiple bool) error { - return me.send(me, &basicAck{ - DeliveryTag: tag, - Multiple: multiple, - }) -} - -/* -Nack negatively acknowledges a delivery by its delivery tag. Prefer this -method to notify the server that you were not able to process this delivery and -it must be redelivered or dropped. - -See also Delivery.Nack -*/ -func (me *Channel) Nack(tag uint64, multiple bool, requeue bool) error { - return me.send(me, &basicNack{ - DeliveryTag: tag, - Multiple: multiple, - Requeue: requeue, - }) -} - -/* -Reject negatively acknowledges a delivery by its delivery tag. Prefer Nack -over Reject when communicating with a RabbitMQ server because you can Nack -multiple messages, reducing the amount of protocol messages to exchange. - -See also Delivery.Reject -*/ -func (me *Channel) Reject(tag uint64, requeue bool) error { - return me.send(me, &basicReject{ - DeliveryTag: tag, - Requeue: requeue, - }) -} diff --git a/vendor/github.com/streadway/amqp/client_test.go b/vendor/github.com/streadway/amqp/client_test.go deleted file mode 100644 index 7d0362845ff..00000000000 --- a/vendor/github.com/streadway/amqp/client_test.go +++ /dev/null @@ -1,559 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -package amqp - -import ( - "bytes" - "io" - "reflect" - "testing" - "time" -) - -type server struct { - *testing.T - r reader // framer <- client - w writer // framer -> client - S io.ReadWriteCloser // Server IO - C io.ReadWriteCloser // Client IO - - // captured client frames - start connectionStartOk - tune connectionTuneOk -} - -func defaultConfig() Config { - return Config{SASL: []Authentication{&PlainAuth{"guest", "guest"}}, Vhost: "/"} -} - -func newSession(t *testing.T) (io.ReadWriteCloser, *server) { - rs, wc := io.Pipe() - rc, ws := io.Pipe() - - rws := &logIO{t, "server", pipe{rs, ws}} - rwc := &logIO{t, "client", pipe{rc, wc}} - - server := server{ - T: t, - r: reader{rws}, - w: writer{rws}, - S: rws, - C: rwc, - } - - return rwc, &server -} - -func (t *server) expectBytes(b []byte) { - in := make([]byte, len(b)) - if _, err := io.ReadFull(t.S, in); err != nil { - t.Fatalf("io error expecting bytes: %v", err) - } - - if bytes.Compare(b, in) != 0 { - t.Fatalf("failed bytes: expected: %s got: %s", string(b), string(in)) - } -} - -func (t *server) send(channel int, m message) { - defer time.AfterFunc(time.Second, func() { panic("send deadlock") }).Stop() - - if err := t.w.WriteFrame(&methodFrame{ - ChannelId: uint16(channel), - Method: m, - }); err != nil { - t.Fatalf("frame err, write: %s", err) - } -} - -// drops all but method frames expected on the given channel -func (t *server) recv(channel int, m message) message { - defer time.AfterFunc(time.Second, func() { panic("recv deadlock") }).Stop() - - var remaining int - var header *headerFrame - var body []byte - - for { - frame, err := t.r.ReadFrame() - if err != nil { - t.Fatalf("frame err, read: %s", err) - } - - if frame.channel() != uint16(channel) { - t.Fatalf("expected frame on channel %d, got channel %d", channel, frame.channel()) - } - - switch f := frame.(type) { - case *heartbeatFrame: - // drop - - case *headerFrame: - // start content state - header = f - remaining = int(header.Size) - if remaining == 0 { - m.(messageWithContent).setContent(header.Properties, nil) - return m - } - - case *bodyFrame: - // continue until terminated - body = append(body, f.Body...) - remaining -= len(f.Body) - if remaining <= 0 { - m.(messageWithContent).setContent(header.Properties, body) - return m - } - - case *methodFrame: - if reflect.TypeOf(m) == reflect.TypeOf(f.Method) { - wantv := reflect.ValueOf(m).Elem() - havev := reflect.ValueOf(f.Method).Elem() - wantv.Set(havev) - if _, ok := m.(messageWithContent); !ok { - return m - } - } else { - t.Fatalf("expected method type: %T, got: %T", m, f.Method) - } - - default: - t.Fatalf("unexpected frame: %+v", f) - } - } - - panic("unreachable") -} - -func (t *server) expectAMQP() { - t.expectBytes([]byte{'A', 'M', 'Q', 'P', 0, 0, 9, 1}) -} - -func (t *server) connectionStart() { - t.send(0, &connectionStart{ - VersionMajor: 0, - VersionMinor: 9, - Mechanisms: "PLAIN", - Locales: "en-us", - }) - - t.recv(0, &t.start) -} - -func (t *server) connectionTune() { - t.send(0, &connectionTune{ - ChannelMax: 11, - FrameMax: 20000, - Heartbeat: 10, - }) - - t.recv(0, &t.tune) -} - -func (t *server) connectionOpen() { - t.expectAMQP() - t.connectionStart() - t.connectionTune() - - t.recv(0, &connectionOpen{}) - t.send(0, &connectionOpenOk{}) -} - -func (t *server) connectionClose() { - t.recv(0, &connectionClose{}) - t.send(0, &connectionCloseOk{}) -} - -func (t *server) channelOpen(id int) { - t.recv(id, &channelOpen{}) - t.send(id, &channelOpenOk{}) -} - -func TestDefaultClientProperties(t *testing.T) { - rwc, srv := newSession(t) - - go func() { - srv.connectionOpen() - rwc.Close() - }() - - if c, err := Open(rwc, defaultConfig()); err != nil { - t.Fatalf("could not create connection: %v (%s)", c, err) - } - - if want, got := defaultProduct, srv.start.ClientProperties["product"]; want != got { - t.Errorf("expected product %s got: %s", want, got) - } - - if want, got := defaultVersion, srv.start.ClientProperties["version"]; want != got { - t.Errorf("expected version %s got: %s", want, got) - } -} - -func TestCustomClientProperties(t *testing.T) { - rwc, srv := newSession(t) - - config := defaultConfig() - config.Properties = Table{ - "product": "foo", - "version": "1.0", - } - - go func() { - srv.connectionOpen() - rwc.Close() - }() - - if c, err := Open(rwc, config); err != nil { - t.Fatalf("could not create connection: %v (%s)", c, err) - } - - if want, got := config.Properties["product"], srv.start.ClientProperties["product"]; want != got { - t.Errorf("expected product %s got: %s", want, got) - } - - if want, got := config.Properties["version"], srv.start.ClientProperties["version"]; want != got { - t.Errorf("expected version %s got: %s", want, got) - } -} - -func TestOpen(t *testing.T) { - rwc, srv := newSession(t) - go func() { - srv.connectionOpen() - rwc.Close() - }() - - if c, err := Open(rwc, defaultConfig()); err != nil { - t.Fatalf("could not create connection: %v (%s)", c, err) - } -} - -func TestChannelOpen(t *testing.T) { - rwc, srv := newSession(t) - - go func() { - srv.connectionOpen() - srv.channelOpen(1) - - rwc.Close() - }() - - c, err := Open(rwc, defaultConfig()) - if err != nil { - t.Fatalf("could not create connection: %v (%s)", c, err) - } - - ch, err := c.Channel() - if err != nil { - t.Fatalf("could not open channel: %v (%s)", ch, err) - } -} - -func TestOpenFailedSASLUnsupportedMechanisms(t *testing.T) { - rwc, srv := newSession(t) - - go func() { - srv.expectAMQP() - srv.send(0, &connectionStart{ - VersionMajor: 0, - VersionMinor: 9, - Mechanisms: "KERBEROS NTLM", - Locales: "en-us", - }) - }() - - c, err := Open(rwc, defaultConfig()) - if err != ErrSASL { - t.Fatalf("expected ErrSASL got: %+v on %+v", err, c) - } -} - -func TestOpenFailedCredentials(t *testing.T) { - rwc, srv := newSession(t) - - go func() { - srv.expectAMQP() - srv.connectionStart() - // Now kill/timeout the connection indicating bad auth - rwc.Close() - }() - - c, err := Open(rwc, defaultConfig()) - if err != ErrCredentials { - t.Fatalf("expected ErrCredentials got: %+v on %+v", err, c) - } -} - -func TestOpenFailedVhost(t *testing.T) { - rwc, srv := newSession(t) - - go func() { - srv.expectAMQP() - srv.connectionStart() - srv.connectionTune() - srv.recv(0, &connectionOpen{}) - - // Now kill/timeout the connection on bad Vhost - rwc.Close() - }() - - c, err := Open(rwc, defaultConfig()) - if err != ErrVhost { - t.Fatalf("expected ErrVhost got: %+v on %+v", err, c) - } -} - -func TestConfirmMultipleOrdersDeliveryTags(t *testing.T) { - rwc, srv := newSession(t) - defer rwc.Close() - - go func() { - srv.connectionOpen() - srv.channelOpen(1) - - srv.recv(1, &confirmSelect{}) - srv.send(1, &confirmSelectOk{}) - - srv.recv(1, &basicPublish{}) - srv.recv(1, &basicPublish{}) - srv.recv(1, &basicPublish{}) - srv.recv(1, &basicPublish{}) - - // Single tag, plus multiple, should produce - // 2, 1, 3, 4 - srv.send(1, &basicAck{DeliveryTag: 2}) - srv.send(1, &basicAck{DeliveryTag: 4, Multiple: true}) - - srv.recv(1, &basicPublish{}) - srv.recv(1, &basicPublish{}) - srv.recv(1, &basicPublish{}) - srv.recv(1, &basicPublish{}) - - // And some more, but in reverse order, multiple then one - // 5, 6, 7, 8 - srv.send(1, &basicAck{DeliveryTag: 6, Multiple: true}) - srv.send(1, &basicAck{DeliveryTag: 8}) - srv.send(1, &basicAck{DeliveryTag: 7}) - }() - - c, err := Open(rwc, defaultConfig()) - if err != nil { - t.Fatalf("could not create connection: %v (%s)", c, err) - } - - ch, err := c.Channel() - if err != nil { - t.Fatalf("could not open channel: %v (%s)", ch, err) - } - - acks, _ := ch.NotifyConfirm(make(chan uint64), make(chan uint64)) - - ch.Confirm(false) - - ch.Publish("", "q", false, false, Publishing{Body: []byte("pub 1")}) - ch.Publish("", "q", false, false, Publishing{Body: []byte("pub 2")}) - ch.Publish("", "q", false, false, Publishing{Body: []byte("pub 3")}) - ch.Publish("", "q", false, false, Publishing{Body: []byte("pub 4")}) - - for i, tag := range []uint64{2, 1, 3, 4} { - if ack := <-acks; tag != ack { - t.Fatalf("failed ack, expected ack#%d to be %d, got %d", i, tag, ack) - } - } - - ch.Publish("", "q", false, false, Publishing{Body: []byte("pub 5")}) - ch.Publish("", "q", false, false, Publishing{Body: []byte("pub 6")}) - ch.Publish("", "q", false, false, Publishing{Body: []byte("pub 7")}) - ch.Publish("", "q", false, false, Publishing{Body: []byte("pub 8")}) - - for i, tag := range []uint64{5, 6, 8, 7} { - if ack := <-acks; tag != ack { - t.Fatalf("failed ack, expected ack#%d to be %d, got %d", i, tag, ack) - } - } - -} - -func TestNotifyClosesReusedPublisherConfirmChan(t *testing.T) { - rwc, srv := newSession(t) - - go func() { - srv.connectionOpen() - srv.channelOpen(1) - - srv.recv(1, &confirmSelect{}) - srv.send(1, &confirmSelectOk{}) - - srv.recv(0, &connectionClose{}) - srv.send(0, &connectionCloseOk{}) - }() - - c, err := Open(rwc, defaultConfig()) - if err != nil { - t.Fatalf("could not create connection: %v (%s)", c, err) - } - - ch, err := c.Channel() - if err != nil { - t.Fatalf("could not open channel: %v (%s)", ch, err) - } - - ackAndNack := make(chan uint64) - ch.NotifyConfirm(ackAndNack, ackAndNack) - - if err := ch.Confirm(false); err != nil { - t.Fatalf("expected to enter confirm mode: %v", err) - } - - if err := c.Close(); err != nil { - t.Fatalf("could not close connection: %v (%s)", c, err) - } -} - -func TestNotifyClosesAllChansAfterConnectionClose(t *testing.T) { - rwc, srv := newSession(t) - - go func() { - srv.connectionOpen() - srv.channelOpen(1) - - srv.recv(0, &connectionClose{}) - srv.send(0, &connectionCloseOk{}) - }() - - c, err := Open(rwc, defaultConfig()) - if err != nil { - t.Fatalf("could not create connection: %v (%s)", c, err) - } - - ch, err := c.Channel() - if err != nil { - t.Fatalf("could not open channel: %v (%s)", ch, err) - } - - if err := c.Close(); err != nil { - t.Fatalf("could not close connection: %v (%s)", c, err) - } - - select { - case <-c.NotifyClose(make(chan *Error)): - case <-time.After(time.Millisecond): - t.Errorf("expected to close NotifyClose chan after Connection.Close") - } - - select { - case <-ch.NotifyClose(make(chan *Error)): - case <-time.After(time.Millisecond): - t.Errorf("expected to close Connection.NotifyClose chan after Connection.Close") - } - - select { - case <-ch.NotifyFlow(make(chan bool)): - case <-time.After(time.Millisecond): - t.Errorf("expected to close Channel.NotifyFlow chan after Connection.Close") - } - - select { - case <-ch.NotifyCancel(make(chan string)): - case <-time.After(time.Millisecond): - t.Errorf("expected to close Channel.NofityCancel chan after Connection.Close") - } - - select { - case <-ch.NotifyReturn(make(chan Return)): - case <-time.After(time.Millisecond): - t.Errorf("expected to close Channel.NotifyReturn chan after Connection.Close") - } - - ack, nack := ch.NotifyConfirm(make(chan uint64), make(chan uint64)) - - select { - case <-ack: - case <-time.After(time.Millisecond): - t.Errorf("expected to close acks on Channel.NotifyConfirm chan after Connection.Close") - } - - select { - case <-nack: - case <-time.After(time.Millisecond): - t.Errorf("expected to close nacks Channel.NotifyConfirm chan after Connection.Close") - } -} - -// Should not panic when sending bodies split at differnet boundaries -func TestPublishBodySliceIssue74(t *testing.T) { - rwc, srv := newSession(t) - defer rwc.Close() - - const frameSize = 100 - const publishings = frameSize * 3 - - done := make(chan bool) - base := make([]byte, publishings) - - go func() { - srv.connectionOpen() - srv.channelOpen(1) - - for i := 0; i < publishings; i++ { - srv.recv(1, &basicPublish{}) - } - - done <- true - }() - - cfg := defaultConfig() - cfg.FrameSize = frameSize - - c, err := Open(rwc, cfg) - if err != nil { - t.Fatalf("could not create connection: %v (%s)", c, err) - } - - ch, err := c.Channel() - if err != nil { - t.Fatalf("could not open channel: %v (%s)", ch, err) - } - - for i := 0; i < publishings; i++ { - go ch.Publish("", "q", false, false, Publishing{Body: base[0:i]}) - } - - <-done -} - -func TestPublishAndShutdownDeadlockIssue84(t *testing.T) { - rwc, srv := newSession(t) - defer rwc.Close() - - go func() { - srv.connectionOpen() - srv.channelOpen(1) - srv.recv(1, &basicPublish{}) - // Mimic a broken io pipe so that Publish catches the error and goes into shutdown - srv.S.Close() - }() - - c, err := Open(rwc, defaultConfig()) - if err != nil { - t.Fatalf("couldn't create connection: %v (%s)", c, err) - } - - ch, err := c.Channel() - if err != nil { - t.Fatalf("couldn't open channel: %v (%s)", ch, err) - } - - defer time.AfterFunc(500*time.Millisecond, func() { panic("Publish deadlock") }).Stop() - for { - if err := ch.Publish("exchange", "q", false, false, Publishing{Body: []byte("test")}); err != nil { - t.Log("successfully caught disconnect error", err) - return - } - } -} diff --git a/vendor/github.com/streadway/amqp/connection.go b/vendor/github.com/streadway/amqp/connection.go deleted file mode 100644 index 5c46f45ac4c..00000000000 --- a/vendor/github.com/streadway/amqp/connection.go +++ /dev/null @@ -1,764 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -package amqp - -import ( - "bufio" - "crypto/tls" - "io" - "net" - "reflect" - "strconv" - "strings" - "sync" - "time" -) - -const ( - defaultHeartbeat = 10 * time.Second - defaultConnectionTimeout = 30 * time.Second - defaultProduct = "https://github.com/streadway/amqp" - defaultVersion = "β" - defaultChannelMax = (2 << 16) - 1 -) - -// Config is used in DialConfig and Open to specify the desired tuning -// parameters used during a connection open handshake. The negotiated tuning -// will be stored in the returned connection's Config field. -type Config struct { - // The SASL mechanisms to try in the client request, and the successful - // mechanism used on the Connection object. - // If SASL is nil, PlainAuth from the URL is used. - SASL []Authentication - - // Vhost specifies the namespace of permissions, exchanges, queues and - // bindings on the server. Dial sets this to the path parsed from the URL. - Vhost string - - ChannelMax int // 0 max channels means 2^16 - 1 - FrameSize int // 0 max bytes means unlimited - Heartbeat time.Duration // less than 1s uses the server's interval - - // TLSClientConfig specifies the client configuration of the TLS connection - // when establishing a tls transport. - // If the URL uses an amqps scheme, then an empty tls.Config with the - // ServerName from the URL is used. - TLSClientConfig *tls.Config - - // Properties is table of properties that the client advertises to the server. - // This is an optional setting - if the application does not set this, - // the underlying library will use a generic set of client properties. - Properties Table - - // Dial returns a net.Conn prepared for a TLS handshake with TSLClientConfig, - // then an AMQP connection handshake. - // If Dial is nil, net.DialTimeout with a 30s connection and 30s read - // deadline is used. - Dial func(network, addr string) (net.Conn, error) -} - -// Connection manages the serialization and deserialization of frames from IO -// and dispatches the frames to the appropriate channel. All RPC methods and -// asyncronous Publishing, Delivery, Ack, Nack and Return messages are -// multiplexed on this channel. There must always be active receivers for -// every asynchronous message on this connection. -type Connection struct { - destructor sync.Once // shutdown once - sendM sync.Mutex // conn writer mutex - m sync.Mutex // struct field mutex - - conn io.ReadWriteCloser - - rpc chan message - writer *writer - sends chan time.Time // timestamps of each frame sent - deadlines chan readDeadliner // heartbeater updates read deadlines - - allocator *allocator // id generator valid after openTune - channels map[uint16]*Channel - - noNotify bool // true when we will never notify again - closes []chan *Error - blocks []chan Blocking - - errors chan *Error - - Config Config // The negotiated Config after connection.open - - Major int // Server's major version - Minor int // Server's minor version - Properties Table // Server properties -} - -type readDeadliner interface { - SetReadDeadline(time.Time) error -} - -type localNetAddr interface { - LocalAddr() net.Addr -} - -// defaultDial establishes a connection when config.Dial is not provided -func defaultDial(network, addr string) (net.Conn, error) { - conn, err := net.DialTimeout(network, addr, defaultConnectionTimeout) - if err != nil { - return nil, err - } - - // Heartbeating hasn't started yet, don't stall forever on a dead server. - if err := conn.SetReadDeadline(time.Now().Add(defaultConnectionTimeout)); err != nil { - return nil, err - } - - return conn, nil -} - -// Dial accepts a string in the AMQP URI format and returns a new Connection -// over TCP using PlainAuth. Defaults to a server heartbeat interval of 10 -// seconds and sets the initial read deadline to 30 seconds. -// -// Dial uses the zero value of tls.Config when it encounters an amqps:// -// scheme. It is equivalent to calling DialTLS(amqp, nil). -func Dial(url string) (*Connection, error) { - return DialConfig(url, Config{ - Heartbeat: defaultHeartbeat, - }) -} - -// DialTLS accepts a string in the AMQP URI format and returns a new Connection -// over TCP using PlainAuth. Defaults to a server heartbeat interval of 10 -// seconds and sets the initial read deadline to 30 seconds. -// -// DialTLS uses the provided tls.Config when encountering an amqps:// scheme. -func DialTLS(url string, amqps *tls.Config) (*Connection, error) { - return DialConfig(url, Config{ - Heartbeat: defaultHeartbeat, - TLSClientConfig: amqps, - }) -} - -// DialConfig accepts a string in the AMQP URI format and a configuration for -// the transport and connection setup, returning a new Connection. Defaults to -// a server heartbeat interval of 10 seconds and sets the initial read deadline -// to 30 seconds. -func DialConfig(url string, config Config) (*Connection, error) { - var err error - var conn net.Conn - - uri, err := ParseURI(url) - if err != nil { - return nil, err - } - - if config.SASL == nil { - config.SASL = []Authentication{uri.PlainAuth()} - } - - if config.Vhost == "" { - config.Vhost = uri.Vhost - } - - if uri.Scheme == "amqps" && config.TLSClientConfig == nil { - config.TLSClientConfig = new(tls.Config) - } - - addr := net.JoinHostPort(uri.Host, strconv.FormatInt(int64(uri.Port), 10)) - - dialer := config.Dial - if dialer == nil { - dialer = defaultDial - } - - conn, err = dialer("tcp", addr) - if err != nil { - return nil, err - } - - if config.TLSClientConfig != nil { - // Use the URI's host for hostname validation unless otherwise set. Make a - // copy so not to modify the caller's reference when the caller reuses a - // tls.Config for a different URL. - if config.TLSClientConfig.ServerName == "" { - c := *config.TLSClientConfig - c.ServerName = uri.Host - config.TLSClientConfig = &c - } - - client := tls.Client(conn, config.TLSClientConfig) - if err := client.Handshake(); err != nil { - conn.Close() - return nil, err - } - - conn = client - } - - return Open(conn, config) -} - -/* -Open accepts an already established connection, or other io.ReadWriteCloser as -a transport. Use this method if you have established a TLS connection or wish -to use your own custom transport. - -*/ -func Open(conn io.ReadWriteCloser, config Config) (*Connection, error) { - me := &Connection{ - conn: conn, - writer: &writer{bufio.NewWriter(conn)}, - channels: make(map[uint16]*Channel), - rpc: make(chan message), - sends: make(chan time.Time), - errors: make(chan *Error, 1), - deadlines: make(chan readDeadliner, 1), - } - go me.reader(conn) - return me, me.open(config) -} - -/* -LocalAddr returns the local TCP peer address, or ":0" (the zero value of net.TCPAddr) -as a fallback default value if the underlying transport does not support LocalAddr(). -*/ -func (me *Connection) LocalAddr() net.Addr { - if c, ok := me.conn.(localNetAddr); ok { - return c.LocalAddr() - } - return &net.TCPAddr{} -} - -/* -NotifyClose registers a listener for close events either initiated by an error -accompaning a connection.close method or by a normal shutdown. - -On normal shutdowns, the chan will be closed. - -To reconnect after a transport or protocol error, register a listener here and -re-run your setup process. - -*/ -func (me *Connection) NotifyClose(c chan *Error) chan *Error { - me.m.Lock() - defer me.m.Unlock() - - if me.noNotify { - close(c) - } else { - me.closes = append(me.closes, c) - } - - return c -} - -/* -NotifyBlock registers a listener for RabbitMQ specific TCP flow control method -extensions connection.blocked and connection.unblocked. Flow control is active -with a reason when Blocking.Blocked is true. When a Connection is blocked, all -methods will block across all connections until server resources become free -again. - -This optional extension is supported by the server when the -"connection.blocked" server capability key is true. - -*/ -func (me *Connection) NotifyBlocked(c chan Blocking) chan Blocking { - me.m.Lock() - defer me.m.Unlock() - - if me.noNotify { - close(c) - } else { - me.blocks = append(me.blocks, c) - } - - return c -} - -/* -Close requests and waits for the response to close the AMQP connection. - -It's advisable to use this message when publishing to ensure all kernel buffers -have been flushed on the server and client before exiting. - -An error indicates that server may not have received this request to close but -the connection should be treated as closed regardless. - -After returning from this call, all resources associated with this connection, -including the underlying io, Channels, Notify listeners and Channel consumers -will also be closed. -*/ -func (me *Connection) Close() error { - defer me.shutdown(nil) - return me.call( - &connectionClose{ - ReplyCode: replySuccess, - ReplyText: "kthxbai", - }, - &connectionCloseOk{}, - ) -} - -func (me *Connection) closeWith(err *Error) error { - defer me.shutdown(err) - return me.call( - &connectionClose{ - ReplyCode: uint16(err.Code), - ReplyText: err.Reason, - }, - &connectionCloseOk{}, - ) -} - -func (me *Connection) send(f frame) error { - me.sendM.Lock() - err := me.writer.WriteFrame(f) - me.sendM.Unlock() - - if err != nil { - // shutdown could be re-entrant from signaling notify chans - go me.shutdown(&Error{ - Code: FrameError, - Reason: err.Error(), - }) - } else { - // Broadcast we sent a frame, reducing heartbeats, only - // if there is something that can receive - like a non-reentrant - // call or if the heartbeater isn't running - select { - case me.sends <- time.Now(): - default: - } - } - - return err -} - -func (me *Connection) shutdown(err *Error) { - me.destructor.Do(func() { - if err != nil { - for _, c := range me.closes { - c <- err - } - } - - for _, ch := range me.channels { - me.closeChannel(ch, err) - } - - if err != nil { - me.errors <- err - } - - me.conn.Close() - - for _, c := range me.closes { - close(c) - } - - for _, c := range me.blocks { - close(c) - } - - me.m.Lock() - me.noNotify = true - me.m.Unlock() - }) -} - -// All methods sent to the connection channel should be synchronous so we -// can handle them directly without a framing component -func (me *Connection) demux(f frame) { - if f.channel() == 0 { - me.dispatch0(f) - } else { - me.dispatchN(f) - } -} - -func (me *Connection) dispatch0(f frame) { - switch mf := f.(type) { - case *methodFrame: - switch m := mf.Method.(type) { - case *connectionClose: - // Send immediately as shutdown will close our side of the writer. - me.send(&methodFrame{ - ChannelId: 0, - Method: &connectionCloseOk{}, - }) - - me.shutdown(newError(m.ReplyCode, m.ReplyText)) - case *connectionBlocked: - for _, c := range me.blocks { - c <- Blocking{Active: true, Reason: m.Reason} - } - case *connectionUnblocked: - for _, c := range me.blocks { - c <- Blocking{Active: false} - } - default: - me.rpc <- m - } - case *heartbeatFrame: - // kthx - all reads reset our deadline. so we can drop this - default: - // lolwat - channel0 only responds to methods and heartbeats - me.closeWith(ErrUnexpectedFrame) - } -} - -func (me *Connection) dispatchN(f frame) { - me.m.Lock() - channel := me.channels[f.channel()] - me.m.Unlock() - - if channel != nil { - channel.recv(channel, f) - } else { - me.dispatchClosed(f) - } -} - -// section 2.3.7: "When a peer decides to close a channel or connection, it -// sends a Close method. The receiving peer MUST respond to a Close with a -// Close-Ok, and then both parties can close their channel or connection. Note -// that if peers ignore Close, deadlock can happen when both peers send Close -// at the same time." -// -// When we don't have a channel, so we must respond with close-ok on a close -// method. This can happen between a channel exception on an asynchronous -// method like basic.publish and a synchronous close with channel.close. -// In that case, we'll get both a channel.close and channel.close-ok in any -// order. -func (me *Connection) dispatchClosed(f frame) { - // Only consider method frames, drop content/header frames - if mf, ok := f.(*methodFrame); ok { - switch mf.Method.(type) { - case *channelClose: - me.send(&methodFrame{ - ChannelId: f.channel(), - Method: &channelCloseOk{}, - }) - case *channelCloseOk: - // we are already closed, so do nothing - default: - // unexpected method on closed channel - me.closeWith(ErrClosed) - } - } -} - -// Reads each frame off the IO and hand off to the connection object that -// will demux the streams and dispatch to one of the opened channels or -// handle on channel 0 (the connection channel). -func (me *Connection) reader(r io.Reader) { - buf := bufio.NewReader(r) - frames := &reader{buf} - conn, haveDeadliner := r.(readDeadliner) - - for { - frame, err := frames.ReadFrame() - - if err != nil { - me.shutdown(&Error{Code: FrameError, Reason: err.Error()}) - return - } - - me.demux(frame) - - if haveDeadliner { - me.deadlines <- conn - } - } -} - -// Ensures that at least one frame is being sent at the tuned interval with a -// jitter tolerance of 1s -func (me *Connection) heartbeater(interval time.Duration, done chan *Error) { - const maxServerHeartbeatsInFlight = 3 - - var sendTicks <-chan time.Time - if interval > 0 { - ticker := time.NewTicker(interval) - defer ticker.Stop() - sendTicks = ticker.C - } - - lastSent := time.Now() - - for { - select { - case at, stillSending := <-me.sends: - // When actively sending, depend on sent frames to reset server timer - if stillSending { - lastSent = at - } else { - return - } - - case at := <-sendTicks: - // When idle, fill the space with a heartbeat frame - if at.Sub(lastSent) > interval-time.Second { - if err := me.send(&heartbeatFrame{}); err != nil { - // send heartbeats even after close/closeOk so we - // tick until the connection starts erroring - return - } - } - - case conn := <-me.deadlines: - // When reading, reset our side of the deadline, if we've negotiated one with - // a deadline that covers at least 2 server heartbeats - if interval > 0 { - conn.SetReadDeadline(time.Now().Add(maxServerHeartbeatsInFlight * interval)) - } - - case <-done: - return - } - } -} - -// Convenience method to inspect the Connection.Properties["capabilities"] -// Table for server identified capabilities like "basic.ack" or -// "confirm.select". -func (me *Connection) isCapable(featureName string) bool { - capabilities, _ := me.Properties["capabilities"].(Table) - hasFeature, _ := capabilities[featureName].(bool) - return hasFeature -} - -// allocateChannel records but does not open a new channel with a unique id. -// This method is the initial part of the channel lifecycle and paired with -// releaseChannel -func (me *Connection) allocateChannel() (*Channel, error) { - me.m.Lock() - defer me.m.Unlock() - - id, ok := me.allocator.next() - if !ok { - return nil, ErrChannelMax - } - - ch := newChannel(me, uint16(id)) - me.channels[uint16(id)] = ch - - return ch, nil -} - -// releaseChannel removes a channel from the registry as the final part of the -// channel lifecycle -func (me *Connection) releaseChannel(id uint16) { - me.m.Lock() - defer me.m.Unlock() - - delete(me.channels, id) - me.allocator.release(int(id)) -} - -// openChannel allocates and opens a channel, must be paired with closeChannel -func (me *Connection) openChannel() (*Channel, error) { - ch, err := me.allocateChannel() - if err != nil { - return nil, err - } - - if err := ch.open(); err != nil { - return nil, err - } - return ch, nil -} - -// closeChannel releases and initiates a shutdown of the channel. All channel -// closures should be initiated here for proper channel lifecycle management on -// this connection. -func (me *Connection) closeChannel(ch *Channel, e *Error) { - ch.shutdown(e) - me.releaseChannel(ch.id) -} - -/* -Channel opens a unique, concurrent server channel to process the bulk of AMQP -messages. Any error from methods on this receiver will render the receiver -invalid and a new Channel should be opened. - -*/ -func (me *Connection) Channel() (*Channel, error) { - return me.openChannel() -} - -func (me *Connection) call(req message, res ...message) error { - // Special case for when the protocol header frame is sent insted of a - // request method - if req != nil { - if err := me.send(&methodFrame{ChannelId: 0, Method: req}); err != nil { - return err - } - } - - select { - case err := <-me.errors: - return err - - case msg := <-me.rpc: - // Try to match one of the result types - for _, try := range res { - if reflect.TypeOf(msg) == reflect.TypeOf(try) { - // *res = *msg - vres := reflect.ValueOf(try).Elem() - vmsg := reflect.ValueOf(msg).Elem() - vres.Set(vmsg) - return nil - } - } - return ErrCommandInvalid - } - - panic("unreachable") -} - -// Connection = open-Connection *use-Connection close-Connection -// open-Connection = C:protocol-header -// S:START C:START-OK -// *challenge -// S:TUNE C:TUNE-OK -// C:OPEN S:OPEN-OK -// challenge = S:SECURE C:SECURE-OK -// use-Connection = *channel -// close-Connection = C:CLOSE S:CLOSE-OK -// / S:CLOSE C:CLOSE-OK -func (me *Connection) open(config Config) error { - if err := me.send(&protocolHeader{}); err != nil { - return err - } - - return me.openStart(config) -} - -func (me *Connection) openStart(config Config) error { - start := &connectionStart{} - - if err := me.call(nil, start); err != nil { - return err - } - - me.Major = int(start.VersionMajor) - me.Minor = int(start.VersionMinor) - me.Properties = Table(start.ServerProperties) - - // eventually support challenge/response here by also responding to - // connectionSecure. - auth, ok := pickSASLMechanism(config.SASL, strings.Split(start.Mechanisms, " ")) - if !ok { - return ErrSASL - } - - // Save this mechanism off as the one we chose - me.Config.SASL = []Authentication{auth} - - return me.openTune(config, auth) -} - -func (me *Connection) openTune(config Config, auth Authentication) error { - if len(config.Properties) == 0 { - config.Properties = Table{ - "product": defaultProduct, - "version": defaultVersion, - } - } - - config.Properties["capabilities"] = Table{ - "connection.blocked": true, - "consumer_cancel_notify": true, - } - - ok := &connectionStartOk{ - Mechanism: auth.Mechanism(), - Response: auth.Response(), - ClientProperties: config.Properties, - } - tune := &connectionTune{} - - if err := me.call(ok, tune); err != nil { - // per spec, a connection can only be closed when it has been opened - // so at this point, we know it's an auth error, but the socket - // was closed instead. Return a meaningful error. - return ErrCredentials - } - - // When the server and client both use default 0, then the max channel is - // only limited by uint16. - me.Config.ChannelMax = pick(config.ChannelMax, int(tune.ChannelMax)) - if me.Config.ChannelMax == 0 { - me.Config.ChannelMax = defaultChannelMax - } - - // Frame size includes headers and end byte (len(payload)+8), even if - // this is less than FrameMinSize, use what the server sends because the - // alternative is to stop the handshake here. - me.Config.FrameSize = pick(config.FrameSize, int(tune.FrameMax)) - - // Save this off for resetDeadline() - me.Config.Heartbeat = time.Second * time.Duration(pick( - int(config.Heartbeat/time.Second), - int(tune.Heartbeat))) - - // "The client should start sending heartbeats after receiving a - // Connection.Tune method" - go me.heartbeater(me.Config.Heartbeat, me.NotifyClose(make(chan *Error, 1))) - - if err := me.send(&methodFrame{ - ChannelId: 0, - Method: &connectionTuneOk{ - ChannelMax: uint16(me.Config.ChannelMax), - FrameMax: uint32(me.Config.FrameSize), - Heartbeat: uint16(me.Config.Heartbeat / time.Second), - }, - }); err != nil { - return err - } - - return me.openVhost(config) -} - -func (me *Connection) openVhost(config Config) error { - req := &connectionOpen{VirtualHost: config.Vhost} - res := &connectionOpenOk{} - - if err := me.call(req, res); err != nil { - // Cannot be closed yet, but we know it's a vhost problem - return ErrVhost - } - - me.Config.Vhost = config.Vhost - - return me.openComplete() -} - -// openComplete performs any final Connection initialization dependent on the -// connection handshake. -func (me *Connection) openComplete() error { - me.allocator = newAllocator(1, me.Config.ChannelMax) - return nil -} - -func pick(client, server int) int { - if client == 0 || server == 0 { - // max - if client > server { - return client - } else { - return server - } - } else { - // min - if client > server { - return server - } else { - return client - } - } - panic("unreachable") -} diff --git a/vendor/github.com/streadway/amqp/consumers.go b/vendor/github.com/streadway/amqp/consumers.go deleted file mode 100644 index b6bd60575ae..00000000000 --- a/vendor/github.com/streadway/amqp/consumers.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -package amqp - -import ( - "fmt" - "os" - "sync" - "sync/atomic" -) - -var consumerSeq uint64 - -func uniqueConsumerTag() string { - return fmt.Sprintf("ctag-%s-%d", os.Args[0], atomic.AddUint64(&consumerSeq, 1)) -} - -type consumerBuffers map[string]chan *Delivery - -// Concurrent type that manages the consumerTag -> -// ingress consumerBuffer mapping -type consumers struct { - sync.Mutex - chans consumerBuffers -} - -func makeConsumers() *consumers { - return &consumers{chans: make(consumerBuffers)} -} - -func bufferDeliveries(in chan *Delivery, out chan Delivery) { - var queue []*Delivery - var queueIn = in - - for delivery := range in { - select { - case out <- *delivery: - // delivered immediately while the consumer chan can receive - default: - queue = append(queue, delivery) - } - - for len(queue) > 0 { - select { - case out <- *queue[0]: - queue = queue[1:] - case delivery, open := <-queueIn: - if open { - queue = append(queue, delivery) - } else { - // stop receiving to drain the queue - queueIn = nil - } - } - } - } - - close(out) -} - -// On key conflict, close the previous channel. -func (me *consumers) add(tag string, consumer chan Delivery) { - me.Lock() - defer me.Unlock() - - if prev, found := me.chans[tag]; found { - close(prev) - } - - in := make(chan *Delivery) - go bufferDeliveries(in, consumer) - - me.chans[tag] = in -} - -func (me *consumers) close(tag string) (found bool) { - me.Lock() - defer me.Unlock() - - ch, found := me.chans[tag] - - if found { - delete(me.chans, tag) - close(ch) - } - - return found -} - -func (me *consumers) closeAll() { - me.Lock() - defer me.Unlock() - - for _, ch := range me.chans { - close(ch) - } - - me.chans = make(consumerBuffers) -} - -// Sends a delivery to a the consumer identified by `tag`. -// If unbuffered channels are used for Consume this method -// could block all deliveries until the consumer -// receives on the other end of the channel. -func (me *consumers) send(tag string, msg *Delivery) bool { - me.Lock() - defer me.Unlock() - - buffer, found := me.chans[tag] - if found { - buffer <- msg - } - - return found -} diff --git a/vendor/github.com/streadway/amqp/delivery.go b/vendor/github.com/streadway/amqp/delivery.go deleted file mode 100644 index f84ae4592ab..00000000000 --- a/vendor/github.com/streadway/amqp/delivery.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -package amqp - -import ( - "errors" - "time" -) - -var errDeliveryNotInitialized = errors.New("delivery not initialized") - -// Acknowledger notifies the server of successful or failed consumption of -// delivieries via identifier found in the Delivery.DeliveryTag field. -// -// Applications can provide mock implementations in tests of Delivery handlers. -type Acknowledger interface { - Ack(tag uint64, multiple bool) error - Nack(tag uint64, multiple bool, requeue bool) error - Reject(tag uint64, requeue bool) error -} - -// Delivery captures the fields for a previously delivered message resident in -// a queue to be delivered by the server to a consumer from Channel.Consume or -// Channel.Get. -type Delivery struct { - Acknowledger Acknowledger // the channel from which this delivery arrived - - Headers Table // Application or header exchange table - - // Properties - ContentType string // MIME content type - ContentEncoding string // MIME content encoding - DeliveryMode uint8 // queue implemention use - non-persistent (1) or persistent (2) - Priority uint8 // queue implementation use - 0 to 9 - CorrelationId string // application use - correlation identifier - ReplyTo string // application use - address to to reply to (ex: RPC) - Expiration string // implementation use - message expiration spec - MessageId string // application use - message identifier - Timestamp time.Time // application use - message timestamp - Type string // application use - message type name - UserId string // application use - creating user - should be authenticated user - AppId string // application use - creating application id - - // Valid only with Channel.Consume - ConsumerTag string - - // Valid only with Channel.Get - MessageCount uint32 - - DeliveryTag uint64 - Redelivered bool - Exchange string // basic.publish exhange - RoutingKey string // basic.publish routing key - - Body []byte -} - -func newDelivery(channel *Channel, msg messageWithContent) *Delivery { - props, body := msg.getContent() - - delivery := Delivery{ - Acknowledger: channel, - - Headers: props.Headers, - ContentType: props.ContentType, - ContentEncoding: props.ContentEncoding, - DeliveryMode: props.DeliveryMode, - Priority: props.Priority, - CorrelationId: props.CorrelationId, - ReplyTo: props.ReplyTo, - Expiration: props.Expiration, - MessageId: props.MessageId, - Timestamp: props.Timestamp, - Type: props.Type, - UserId: props.UserId, - AppId: props.AppId, - - Body: body, - } - - // Properties for the delivery types - switch m := msg.(type) { - case *basicDeliver: - delivery.ConsumerTag = m.ConsumerTag - delivery.DeliveryTag = m.DeliveryTag - delivery.Redelivered = m.Redelivered - delivery.Exchange = m.Exchange - delivery.RoutingKey = m.RoutingKey - - case *basicGetOk: - delivery.MessageCount = m.MessageCount - delivery.DeliveryTag = m.DeliveryTag - delivery.Redelivered = m.Redelivered - delivery.Exchange = m.Exchange - delivery.RoutingKey = m.RoutingKey - } - - return &delivery -} - -/* -Ack delegates an acknowledgement through the Acknowledger interface that the -client or server has finished work on a delivery. - -All deliveries in AMQP must be acknowledged. If you called Channel.Consume -with autoAck true then the server will be automatically ack each message and -this method should not be called. Otherwise, you must call Delivery.Ack after -you have successfully processed this delivery. - -When multiple is true, this delivery and all prior unacknowledged deliveries -on the same channel will be acknowledged. This is useful for batch processing -of deliveries. - -An error will indicate that the acknowledge could not be delivered to the -channel it was sent from. - -Either Delivery.Ack, Delivery.Reject or Delivery.Nack must be called for every -delivery that is not automatically acknowledged. -*/ -func (me Delivery) Ack(multiple bool) error { - if me.Acknowledger == nil { - return errDeliveryNotInitialized - } - return me.Acknowledger.Ack(me.DeliveryTag, multiple) -} - -/* -Reject delegates a negatively acknowledgement through the Acknowledger interface. - -When requeue is true, queue this message to be delivered to a consumer on a -different channel. When requeue is false or the server is unable to queue this -message, it will be dropped. - -If you are batch processing deliveries, and your server supports it, prefer -Delivery.Nack. - -Either Delivery.Ack, Delivery.Reject or Delivery.Nack must be called for every -delivery that is not automatically acknowledged. -*/ -func (me Delivery) Reject(requeue bool) error { - if me.Acknowledger == nil { - return errDeliveryNotInitialized - } - return me.Acknowledger.Reject(me.DeliveryTag, requeue) -} - -/* -Nack negatively acknowledge the delivery of message(s) identified by the -delivery tag from either the client or server. - -When multiple is true, nack messages up to and including delivered messages up -until the delivery tag delivered on the same channel. - -When requeue is true, request the server to deliver this message to a different -consumer. If it is not possible or requeue is false, the message will be -dropped or delivered to a server configured dead-letter queue. - -This method must not be used to select or requeue messages the client wishes -not to handle, rather it is to inform the server that the client is incapable -of handling this message at this time. - -Either Delivery.Ack, Delivery.Reject or Delivery.Nack must be called for every -delivery that is not automatically acknowledged. -*/ -func (me Delivery) Nack(multiple, requeue bool) error { - if me.Acknowledger == nil { - return errDeliveryNotInitialized - } - return me.Acknowledger.Nack(me.DeliveryTag, multiple, requeue) -} diff --git a/vendor/github.com/streadway/amqp/delivery_test.go b/vendor/github.com/streadway/amqp/delivery_test.go deleted file mode 100644 index f126f87d8f3..00000000000 --- a/vendor/github.com/streadway/amqp/delivery_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package amqp - -import "testing" - -func shouldNotPanic(t *testing.T) { - if err := recover(); err != nil { - t.Fatalf("should not panic, got: %s", err) - } -} - -// A closed delivery chan could produce zero value. Ack/Nack/Reject on these -// deliveries can produce a nil pointer panic. Instead return an error when -// the method can never be successful. -func TestAckZeroValueAcknowledgerDoesNotPanic(t *testing.T) { - defer shouldNotPanic(t) - if err := (Delivery{}).Ack(false); err == nil { - t.Errorf("expected Delivery{}.Ack to error") - } -} - -func TestNackZeroValueAcknowledgerDoesNotPanic(t *testing.T) { - defer shouldNotPanic(t) - if err := (Delivery{}).Nack(false, false); err == nil { - t.Errorf("expected Delivery{}.Ack to error") - } -} - -func TestRejectZeroValueAcknowledgerDoesNotPanic(t *testing.T) { - defer shouldNotPanic(t) - if err := (Delivery{}).Reject(false); err == nil { - t.Errorf("expected Delivery{}.Ack to error") - } -} diff --git a/vendor/github.com/streadway/amqp/doc.go b/vendor/github.com/streadway/amqp/doc.go deleted file mode 100644 index 94c29f825a1..00000000000 --- a/vendor/github.com/streadway/amqp/doc.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -/* -AMQP 0.9.1 client with RabbitMQ extensions - -Understand the AMQP 0.9.1 messaging model by reviewing these links first. Much -of the terminology in this library directly relates to AMQP concepts. - - Resources - - http://www.rabbitmq.com/tutorials/amqp-concepts.html - http://www.rabbitmq.com/getstarted.html - http://www.rabbitmq.com/amqp-0-9-1-reference.html - -Design - -Most other broker clients publish to queues, but in AMQP, clients publish -Exchanges instead. AMQP is programmable, meaning that both the producers and -consumers agree on the configuration of the broker, instead requiring an -operator or system configuration that declares the logical topology in the -broker. The routing between producers and consumer queues is via Bindings. -These bindings form the logical topology of the broker. - -In this library, a message sent from publisher is called a "Publishing" and a -message received to a consumer is called a "Delivery". The fields of -Publishings and Deliveries are close but not exact mappings to the underlying -wire format to maintain stronger types. Many other libraries will combine -message properties with message headers. In this library, the message well -known properties are strongly typed fields on the Publishings and Deliveries, -whereas the user defined headers are in the Headers field. - -The method naming closely matches the protocol's method name with positional -parameters mapping to named protocol message fields. The motivation here is to -present a comprehensive view over all possible interactions with the server. - -Generally, methods that map to protocol methods of the "basic" class will be -elided in this interface, and "select" methods of various channel mode selectors -will be elided for example Channel.Confirm and Channel.Tx. - -The library is intentionally designed to be synchronous, where responses for -each protocol message are required to be received in an RPC manner. Some -methods have a noWait parameter like Channel.QueueDeclare, and some methods are -asynchronous like Channel.Publish. The error values should still be checked for -these methods as they will indicate IO failures like when the underlying -connection closes. - -Asynchronous Events - -Clients of this library may be interested in receiving some of the protocol -messages other than Deliveries like basic.ack methods while a channel is in -confirm mode. - -The Notify* methods with Connection and Channel receivers model the pattern of -asynchronous events like closes due to exceptions, or messages that are sent out -of band from an RPC call like basic.ack or basic.flow. - -Any asynchronous events, including Deliveries and Publishings must always have -a receiver until the corresponding chans are closed. Without asynchronous -receivers, the sychronous methods will block. - -Use Case - -It's important as a client to an AMQP topology to ensure the state of the -broker matches your expectations. For both publish and consume use cases, -make sure you declare the queues, exchanges and bindings you expect to exist -prior to calling Channel.Publish or Channel.Consume. - - // Connections start with amqp.Dial() typically from a command line argument - // or environment variable. - connection, err := amqp.Dial(os.Getenv("AMQP_URL")) - - // To cleanly shutdown by flushing kernel buffers, make sure to close and - // wait for the response. - defer connection.Close() - - // Most operations happen on a channel. If any error is returned on a - // channel, the channel will no longer be valid, throw it away and try with - // a different channel. If you use many channels, it's useful for the - // server to - channel, err := connection.Channel() - - // Declare your topology here, if it doesn't exist, it will be created, if - // it existed already and is not what you expect, then that's considered an - // error. - - // Use your connection on this topology with either Publish or Consume, or - // inspect your queues with QueueInspect. It's unwise to mix Publish and - // Consume to let TCP do its job well. - -SSL/TLS - Secure connections - -When Dial encounters an amqps:// scheme, it will use the zero value of a -tls.Config. This will only perform server certificate and host verification. - -Use DialTLS when you wish to provide a client certificate (recommended), -include a private certificate authority's certificate in the cert chain for -server validity, or run insecure by not verifying the server certificate dial -your own connection. DialTLS will use the provided tls.Config when it -encounters an amqps:// scheme and will dial a plain connection when it -encounters an amqp:// scheme. - -SSL/TLS in RabbitMQ is documented here: http://www.rabbitmq.com/ssl.html - -*/ -package amqp diff --git a/vendor/github.com/streadway/amqp/examples_test.go b/vendor/github.com/streadway/amqp/examples_test.go deleted file mode 100644 index 6b581816afe..00000000000 --- a/vendor/github.com/streadway/amqp/examples_test.go +++ /dev/null @@ -1,395 +0,0 @@ -package amqp_test - -import ( - "crypto/tls" - "crypto/x509" - "github.com/streadway/amqp" - "io/ioutil" - "log" - "net" - "runtime" - "time" -) - -func ExampleConfig_timeout() { - // Provide your own anonymous Dial function that delgates to net.DialTimout - // for custom timeouts - - conn, err := amqp.DialConfig("amqp:///", amqp.Config{ - Dial: func(network, addr string) (net.Conn, error) { - return net.DialTimeout(network, addr, 2*time.Second) - }, - }) - - log.Printf("conn: %v, err: %v", conn, err) -} - -func ExampleDialTLS() { - // To get started with SSL/TLS follow the instructions for adding SSL/TLS - // support in RabbitMQ with a private certificate authority here: - // - // http://www.rabbitmq.com/ssl.html - // - // Then in your rabbitmq.config, disable the plain AMQP port, verify clients - // and fail if no certificate is presented with the following: - // - // [ - // {rabbit, [ - // {tcp_listeners, []}, % listens on 127.0.0.1:5672 - // {ssl_listeners, [5671]}, % listens on 0.0.0.0:5671 - // {ssl_options, [{cacertfile,"/path/to/your/testca/cacert.pem"}, - // {certfile,"/path/to/your/server/cert.pem"}, - // {keyfile,"/path/to/your/server/key.pem"}, - // {verify,verify_peer}, - // {fail_if_no_peer_cert,true}]} - // ]} - // ]. - - cfg := new(tls.Config) - - // The self-signing certificate authority's certificate must be included in - // the RootCAs to be trusted so that the server certificate can be verified. - // - // Alternatively to adding it to the tls.Config you can add the CA's cert to - // your system's root CAs. The tls package will use the system roots - // specific to each support OS. Under OS X, add (drag/drop) your cacert.pem - // file to the 'Certificates' section of KeyChain.app to add and always - // trust. - // - // Or with the command line add and trust the DER encoded certificate: - // - // security add-certificate testca/cacert.cer - // security add-trusted-cert testca/cacert.cer - // - // If you depend on the system root CAs, then use nil for the RootCAs field - // so the system roots will be loaded. - - cfg.RootCAs = x509.NewCertPool() - - if ca, err := ioutil.ReadFile("testca/cacert.pem"); err == nil { - cfg.RootCAs.AppendCertsFromPEM(ca) - } - - // Move the client cert and key to a location specific to your application - // and load them here. - - if cert, err := tls.LoadX509KeyPair("client/cert.pem", "client/key.pem"); err == nil { - cfg.Certificates = append(cfg.Certificates, cert) - } - - // Server names are validated by the crypto/tls package, so the server - // certificate must be made for the hostname in the URL. Find the commonName - // (CN) and make sure the hostname in the URL matches this common name. Per - // the RabbitMQ instructions for a self-signed cert, this defautls to the - // current hostname. - // - // openssl x509 -noout -in server/cert.pem -subject - // - // If your server name in your certificate is different than the host you are - // connecting to, set the hostname used for verification in - // ServerName field of the tls.Config struct. - - conn, err := amqp.DialTLS("amqps://server-name-from-certificate/", cfg) - - log.Printf("conn: %v, err: %v", conn, err) -} - -func ExampleChannel_Confirm_bridge() { - // This example acts as a bridge, shoveling all messages sent from the source - // exchange "log" to destination exchange "log". - - // Confirming publishes can help from overproduction and ensure every message - // is delivered. - - // Setup the source of the store and forward - source, err := amqp.Dial("amqp://source/") - if err != nil { - log.Fatalf("connection.open source: %s", err) - } - defer source.Close() - - chs, err := source.Channel() - if err != nil { - log.Fatalf("channel.open source: %s", err) - } - - if err := chs.ExchangeDeclare("log", "topic", true, false, false, false, nil); err != nil { - log.Fatalf("exchange.declare destination: %s", err) - } - - if _, err := chs.QueueDeclare("remote-tee", true, true, false, false, nil); err != nil { - log.Fatalf("queue.declare source: %s", err) - } - - if err := chs.QueueBind("remote-tee", "#", "logs", false, nil); err != nil { - log.Fatalf("queue.bind source: %s", err) - } - - shovel, err := chs.Consume("remote-tee", "shovel", false, false, false, false, nil) - if err != nil { - log.Fatalf("basic.consume source: %s", err) - } - - // Setup the destination of the store and forward - destination, err := amqp.Dial("amqp://destination/") - if err != nil { - log.Fatalf("connection.open destination: %s", err) - } - defer destination.Close() - - chd, err := destination.Channel() - if err != nil { - log.Fatalf("channel.open destination: %s", err) - } - - if err := chd.ExchangeDeclare("log", "topic", true, false, false, false, nil); err != nil { - log.Fatalf("exchange.declare destination: %s", err) - } - - // Buffer of 1 for our single outstanding publishing - pubAcks, pubNacks := chd.NotifyConfirm(make(chan uint64, 1), make(chan uint64, 1)) - - if err := chd.Confirm(false); err != nil { - log.Fatalf("confirm.select destination: %s", err) - } - - // Now pump the messages, one by one, a smarter implementation - // would batch the deliveries and use multiple ack/nacks - for { - msg, ok := <-shovel - if !ok { - log.Fatalf("source channel closed, see the reconnect example for handling this") - } - - err = chd.Publish("logs", msg.RoutingKey, false, false, amqp.Publishing{ - // Copy all the properties - ContentType: msg.ContentType, - ContentEncoding: msg.ContentEncoding, - DeliveryMode: msg.DeliveryMode, - Priority: msg.Priority, - CorrelationId: msg.CorrelationId, - ReplyTo: msg.ReplyTo, - Expiration: msg.Expiration, - MessageId: msg.MessageId, - Timestamp: msg.Timestamp, - Type: msg.Type, - UserId: msg.UserId, - AppId: msg.AppId, - - // Custom headers - Headers: msg.Headers, - - // And the body - Body: msg.Body, - }) - - if err != nil { - msg.Nack(false, false) - log.Fatalf("basic.publish destination: %s", msg) - } - - // only ack the source delivery when the destination acks the publishing - // here you could check for delivery order by keeping a local state of - // expected delivery tags - select { - case <-pubAcks: - msg.Ack(false) - case <-pubNacks: - msg.Nack(false, false) - } - } -} - -func ExampleChannel_Consume() { - // Connects opens an AMQP connection from the credentials in the URL. - conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") - if err != nil { - log.Fatalf("connection.open: %s", err) - } - defer conn.Close() - - c, err := conn.Channel() - if err != nil { - log.Fatalf("channel.open: %s", err) - } - - // We declare our topology on both the publisher and consumer to ensure they - // are the same. This is part of AMQP being a programmable messaging model. - // - // See the Channel.Publish example for the complimentary declare. - err = c.ExchangeDeclare("logs", "topic", true, false, false, false, nil) - if err != nil { - log.Fatalf("exchange.declare: %s", err) - } - - // Establish our queue topologies that we are responsible for - type bind struct { - queue string - key string - } - - bindings := []bind{ - bind{"page", "alert"}, - bind{"email", "info"}, - bind{"firehose", "#"}, - } - - for _, b := range bindings { - _, err = c.QueueDeclare(b.queue, true, false, false, false, nil) - if err != nil { - log.Fatalf("queue.declare: %v", err) - } - - err = c.QueueBind(b.queue, b.key, "logs", false, nil) - if err != nil { - log.Fatalf("queue.bind: %v", err) - } - } - - // Set our quality of service. Since we're sharing 3 consumers on the same - // channel, we want at least 3 messages in flight. - err = c.Qos(3, 0, false) - if err != nil { - log.Fatalf("basic.qos: %v", err) - } - - // Establish our consumers that have different responsibilities. Our first - // two queues do not ack the messages on the server, so require to be acked - // on the client. - - pages, err := c.Consume("page", "pager", false, false, false, false, nil) - if err != nil { - log.Fatalf("basic.consume: %v", err) - } - - go func() { - for log := range pages { - // ... this consumer is responsible for sending pages per log - log.Ack(false) - } - }() - - // Notice how the concern for which messages arrive here are in the AMQP - // topology and not in the queue. We let the server pick a consumer tag this - // time. - - emails, err := c.Consume("email", "", false, false, false, false, nil) - if err != nil { - log.Fatalf("basic.consume: %v", err) - } - - go func() { - for log := range emails { - // ... this consumer is responsible for sending emails per log - log.Ack(false) - } - }() - - // This consumer requests that every message is acknowledged as soon as it's - // delivered. - - firehose, err := c.Consume("firehose", "", true, false, false, false, nil) - if err != nil { - log.Fatalf("basic.consume: %v", err) - } - - // To show how to process the items in parallel, we'll use a work pool. - for i := 0; i < runtime.NumCPU(); i++ { - go func(work <-chan amqp.Delivery) { - for _ = range work { - // ... this consumer pulls from the firehose and doesn't need to acknowledge - } - }(firehose) - } - - // Wait until you're ready to finish, could be a signal handler here. - time.Sleep(10 * time.Second) - - // Cancelling a consumer by name will finish the range and gracefully end the - // goroutine - err = c.Cancel("pager", false) - if err != nil { - log.Fatalf("basic.cancel: %v", err) - } - - // deferred closing the Connection will also finish the consumer's ranges of - // their delivery chans. If you need every delivery to be processed, make - // sure to wait for all consumers goroutines to finish before exiting your - // process. -} - -func ExampleChannel_Publish() { - // Connects opens an AMQP connection from the credentials in the URL. - conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") - if err != nil { - log.Fatalf("connection.open: %s", err) - } - - // This waits for a server acknowledgment which means the sockets will have - // flushed all outbound publishings prior to returning. It's important to - // block on Close to not lose any publishings. - defer conn.Close() - - c, err := conn.Channel() - if err != nil { - log.Fatalf("channel.open: %s", err) - } - - // We declare our topology on both the publisher and consumer to ensure they - // are the same. This is part of AMQP being a programmable messaging model. - // - // See the Channel.Consume example for the complimentary declare. - err = c.ExchangeDeclare("logs", "topic", true, false, false, false, nil) - if err != nil { - log.Fatalf("exchange.declare: %v", err) - } - - // Prepare this message to be persistent. Your publishing requirements may - // be different. - msg := amqp.Publishing{ - DeliveryMode: amqp.Persistent, - Timestamp: time.Now(), - ContentType: "text/plain", - Body: []byte("Go Go AMQP!"), - } - - // This is not a mandatory delivery, so it will be dropped if there are no - // queues bound to the logs exchange. - err = c.Publish("logs", "info", false, false, msg) - if err != nil { - // Since publish is asynchronous this can happen if the network connection - // is reset or if the server has run out of resources. - log.Fatalf("basic.publish: %v", err) - } -} - -func publishAllTheThings(conn *amqp.Connection) { - // ... snarf snarf, barf barf -} - -func ExampleConnection_NotifyBlocked() { - // Simply logs when the server throttles the TCP connection for publishers - - // Test this by tuning your server to have a low memory watermark: - // rabbitmqctl set_vm_memory_high_watermark 0.00000001 - - conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") - if err != nil { - log.Fatalf("connection.open: %s", err) - } - defer conn.Close() - - blockings := conn.NotifyBlocked(make(chan amqp.Blocking)) - go func() { - for b := range blockings { - if b.Active { - log.Printf("TCP blocked: %q", b.Reason) - } else { - log.Printf("TCP unblocked") - } - } - }() - - // Your application domain channel setup publishings - publishAllTheThings(conn) -} diff --git a/vendor/github.com/streadway/amqp/gen.sh b/vendor/github.com/streadway/amqp/gen.sh deleted file mode 100644 index d46e19bd812..00000000000 --- a/vendor/github.com/streadway/amqp/gen.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -go run spec/gen.go < spec/amqp0-9-1.stripped.extended.xml | gofmt > spec091.go diff --git a/vendor/github.com/streadway/amqp/integration_test.go b/vendor/github.com/streadway/amqp/integration_test.go deleted file mode 100644 index 5db5b067d37..00000000000 --- a/vendor/github.com/streadway/amqp/integration_test.go +++ /dev/null @@ -1,1772 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -// +build integration - -package amqp - -import ( - "bytes" - devrand "crypto/rand" - "encoding/binary" - "fmt" - "hash/crc32" - "io" - "math/rand" - "net" - "os" - "reflect" - "strconv" - "testing" - "testing/quick" - "time" -) - -func TestIntegrationOpenClose(t *testing.T) { - if c := integrationConnection(t, "open-close"); c != nil { - t.Logf("have connection, calling connection close") - if err := c.Close(); err != nil { - t.Fatalf("connection close: %s", err) - } - t.Logf("connection close OK") - } -} - -func TestIntegrationOpenCloseChannel(t *testing.T) { - if c := integrationConnection(t, "channel"); c != nil { - defer c.Close() - - if _, err := c.Channel(); err != nil { - t.Errorf("Channel could not be opened: %s", err) - } - } -} - -func TestIntegrationOpenConfig(t *testing.T) { - config := Config{} - - c, err := DialConfig(integrationURLFromEnv(), config) - if err != nil { - t.Errorf("expected to dial with config %+v integration server: %s", config, err) - } - - if _, err := c.Channel(); err != nil { - t.Fatalf("expected to open channel: %s", err) - } - - if err := c.Close(); err != nil { - t.Fatalf("connection close: %s", err) - } -} - -func TestIntegrationOpenConfigWithNetDial(t *testing.T) { - config := Config{Dial: net.Dial} - - c, err := DialConfig(integrationURLFromEnv(), config) - if err != nil { - t.Errorf("expected to dial with config %+v integration server: %s", config, err) - } - - if _, err := c.Channel(); err != nil { - t.Fatalf("expected to open channel: %s", err) - } - - if err := c.Close(); err != nil { - t.Fatalf("connection close: %s", err) - } -} - -func TestIntegrationLocalAddr(t *testing.T) { - config := Config{} - - c, err := DialConfig(integrationURLFromEnv(), config) - defer c.Close() - if err != nil { - t.Errorf("expected to dial with config %+v integration server: %s", config, err) - } - - a := c.LocalAddr() - _, portString, err := net.SplitHostPort(a.String()) - if err != nil { - t.Errorf("expected to get a local network address with config %+v integration server: %s", config, a.String()) - } - - port, err := strconv.Atoi(portString) - if err != nil { - t.Errorf("expected to get a TCP port number with config %+v integration server: %s", config, err) - } - t.Logf("Connected to port %d\n", port) -} - -// https://github.com/streadway/amqp/issues/94 -func TestExchangePassiveOnMissingExchangeShouldError(t *testing.T) { - c := integrationConnection(t, "exch") - if c != nil { - defer c.Close() - - ch, err := c.Channel() - if err != nil { - t.Fatalf("create channel 1: %s", err) - } - defer ch.Close() - - if err := ch.ExchangeDeclarePassive( - "test-integration-missing-passive-exchange", - "direct", // type - false, // duration (note: is durable) - true, // auto-delete - false, // internal - false, // nowait - nil, // args - ); err == nil { - t.Fatal("ExchangeDeclarePassive of a missing exchange should return error") - } - } -} - -// https://github.com/streadway/amqp/issues/94 -func TestIntegrationExchangeDeclarePassiveOnDeclaredShouldNotError(t *testing.T) { - c := integrationConnection(t, "exch") - if c != nil { - defer c.Close() - - exchange := "test-integration-decalred-passive-exchange" - - ch, err := c.Channel() - if err != nil { - t.Fatalf("create channel: %s", err) - } - defer ch.Close() - - if err := ch.ExchangeDeclare( - exchange, // name - "direct", // type - false, // durable - true, // auto-delete - false, // internal - false, // nowait - nil, // args - ); err != nil { - t.Fatalf("declare exchange: %s", err) - } - - if err := ch.ExchangeDeclarePassive( - exchange, // name - "direct", // type - false, // durable - true, // auto-delete - false, // internal - false, // nowait - nil, // args - ); err != nil { - t.Fatalf("ExchangeDeclarePassive on a declared exchange should not error, got: %q", err) - } - } -} - -func TestIntegrationExchange(t *testing.T) { - c := integrationConnection(t, "exch") - if c != nil { - defer c.Close() - - channel, err := c.Channel() - if err != nil { - t.Fatalf("create channel: %s", err) - } - t.Logf("create channel OK") - - exchange := "test-integration-exchange" - - if err := channel.ExchangeDeclare( - exchange, // name - "direct", // type - false, // duration - true, // auto-delete - false, // internal - false, // nowait - nil, // args - ); err != nil { - t.Fatalf("declare exchange: %s", err) - } - t.Logf("declare exchange OK") - - if err := channel.ExchangeDelete(exchange, false, false); err != nil { - t.Fatalf("delete exchange: %s", err) - } - t.Logf("delete exchange OK") - - if err := channel.Close(); err != nil { - t.Fatalf("close channel: %s", err) - } - t.Logf("close channel OK") - } -} - -// https://github.com/streadway/amqp/issues/94 -func TestIntegrationQueueDeclarePassiveOnMissingExchangeShouldError(t *testing.T) { - c := integrationConnection(t, "queue") - if c != nil { - defer c.Close() - - ch, err := c.Channel() - if err != nil { - t.Fatalf("create channel1: %s", err) - } - defer ch.Close() - - if _, err := ch.QueueDeclarePassive( - "test-integration-missing-passive-queue", // name - false, // duration (note: not durable) - true, // auto-delete - false, // exclusive - false, // noWait - nil, // arguments - ); err == nil { - t.Fatal("QueueDeclarePassive of a missing queue should error") - } - } -} - -// https://github.com/streadway/amqp/issues/94 -func TestIntegrationPassiveQueue(t *testing.T) { - c := integrationConnection(t, "queue") - if c != nil { - defer c.Close() - - name := "test-integration-declared-passive-queue" - - ch, err := c.Channel() - if err != nil { - t.Fatalf("create channel1: %s", err) - } - defer ch.Close() - - if _, err := ch.QueueDeclare( - name, // name - false, // durable - true, // auto-delete - false, // exclusive - false, // noWait - nil, // arguments - ); err != nil { - t.Fatalf("queue declare: %s", err) - } - - if _, err := ch.QueueDeclarePassive( - name, // name - false, // durable - true, // auto-delete - false, // exclusive - false, // noWait - nil, // arguments - ); err != nil { - t.Fatalf("QueueDeclarePassive on declared queue should not error, got: %q", err) - } - - if _, err := ch.QueueDeclarePassive( - name, // name - true, // durable (note: differs) - true, // auto-delete - false, // exclusive - false, // noWait - nil, // arguments - ); err != nil { - t.Fatalf("QueueDeclarePassive on declared queue with different flags should error") - } - } -} - -func TestIntegrationBasicQueueOperations(t *testing.T) { - c := integrationConnection(t, "queue") - if c != nil { - defer c.Close() - - channel, err := c.Channel() - if err != nil { - t.Fatalf("create channel: %s", err) - } - t.Logf("create channel OK") - - exchangeName := "test-basic-ops-exchange" - queueName := "test-basic-ops-queue" - - deleteQueueFirstOptions := []bool{true, false} - for _, deleteQueueFirst := range deleteQueueFirstOptions { - - if err := channel.ExchangeDeclare( - exchangeName, // name - "direct", // type - true, // duration (note: is durable) - false, // auto-delete - false, // internal - false, // nowait - nil, // args - ); err != nil { - t.Fatalf("declare exchange: %s", err) - } - t.Logf("declare exchange OK") - - if _, err := channel.QueueDeclare( - queueName, // name - true, // duration (note: durable) - false, // auto-delete - false, // exclusive - false, // noWait - nil, // arguments - ); err != nil { - t.Fatalf("queue declare: %s", err) - } - t.Logf("declare queue OK") - - if err := channel.QueueBind( - queueName, // name - "", // routingKey - exchangeName, // sourceExchange - false, // noWait - nil, // arguments - ); err != nil { - t.Fatalf("queue bind: %s", err) - } - t.Logf("queue bind OK") - - if deleteQueueFirst { - if _, err := channel.QueueDelete( - queueName, // name - false, // ifUnused (false=be aggressive) - false, // ifEmpty (false=be aggressive) - false, // noWait - ); err != nil { - t.Fatalf("delete queue (first): %s", err) - } - t.Logf("delete queue (first) OK") - - if err := channel.ExchangeDelete(exchangeName, false, false); err != nil { - t.Fatalf("delete exchange (after delete queue): %s", err) - } - t.Logf("delete exchange (after delete queue) OK") - - } else { // deleteExchangeFirst - if err := channel.ExchangeDelete(exchangeName, false, false); err != nil { - t.Fatalf("delete exchange (first): %s", err) - } - t.Logf("delete exchange (first) OK") - - if _, err := channel.QueueInspect(queueName); err != nil { - t.Fatalf("inspect queue state after deleting exchange: %s", err) - } - t.Logf("queue properly remains after exchange is deleted") - - if _, err := channel.QueueDelete( - queueName, - false, // ifUnused - false, // ifEmpty - false, // noWait - ); err != nil { - t.Fatalf("delete queue (after delete exchange): %s", err) - } - t.Logf("delete queue (after delete exchange) OK") - } - } - - if err := channel.Close(); err != nil { - t.Fatalf("close channel: %s", err) - } - t.Logf("close channel OK") - } -} - -func TestIntegrationConnectionNegotiatesMaxChannels(t *testing.T) { - config := Config{ChannelMax: 0} - - c, err := DialConfig(integrationURLFromEnv(), config) - if err != nil { - t.Errorf("expected to dial with config %+v integration server: %s", config, err) - } - defer c.Close() - - if want, got := defaultChannelMax, c.Config.ChannelMax; want != got { - t.Fatalf("expected connection to negotiate uint16 (%d) channels, got: %d", want, got) - } -} - -func TestIntegrationConnectionNegotiatesClientMaxChannels(t *testing.T) { - config := Config{ChannelMax: 16} - - c, err := DialConfig(integrationURLFromEnv(), config) - if err != nil { - t.Errorf("expected to dial with config %+v integration server: %s", config, err) - } - defer c.Close() - - if want, got := config.ChannelMax, c.Config.ChannelMax; want != got { - t.Fatalf("expected client specified channel limit after handshake %d, got: %d", want, got) - } -} - -func TestIntegrationChannelIDsExhausted(t *testing.T) { - config := Config{ChannelMax: 16} - - c, err := DialConfig(integrationURLFromEnv(), config) - if err != nil { - t.Errorf("expected to dial with config %+v integration server: %s", config, err) - } - defer c.Close() - - for i := 1; i <= c.Config.ChannelMax; i++ { - if _, err := c.Channel(); err != nil { - t.Fatalf("expected allocating all channel ids to succed, failed on %d with %v", i, err) - } - } - - if _, err := c.Channel(); err != ErrChannelMax { - t.Fatalf("expected allocating all channels to produce the client side error %#v, got: %#v", ErrChannelMax, err) - } -} - -func TestIntegrationChannelClosing(t *testing.T) { - c := integrationConnection(t, "closings") - if c != nil { - defer c.Close() - - // This function is run on every channel after it is successfully - // opened. It can do something to verify something. It should be - // quick; many channels may be opened! - f := func(t *testing.T, c *Channel) { - return - } - - // open and close - channel, err := c.Channel() - if err != nil { - t.Fatalf("basic create channel: %s", err) - } - t.Logf("basic create channel OK") - - if err := channel.Close(); err != nil { - t.Fatalf("basic close channel: %s", err) - } - t.Logf("basic close channel OK") - - // deferred close - signal := make(chan bool) - go func() { - channel, err := c.Channel() - if err != nil { - t.Fatalf("second create channel: %s", err) - } - t.Logf("second create channel OK") - - <-signal // a bit of synchronization - f(t, channel) - - defer func() { - if err := channel.Close(); err != nil { - t.Fatalf("deferred close channel: %s", err) - } - t.Logf("deferred close channel OK") - signal <- true - }() - }() - signal <- true - select { - case <-signal: - t.Logf("(got close signal OK)") - break - case <-time.After(250 * time.Millisecond): - t.Fatalf("deferred close: timeout") - } - - // multiple channels - for _, n := range []int{2, 4, 8, 16, 32, 64, 128, 256} { - channels := make([]*Channel, n) - for i := 0; i < n; i++ { - var err error - if channels[i], err = c.Channel(); err != nil { - t.Fatalf("create channel %d/%d: %s", i+1, n, err) - } - } - f(t, channel) - for i, channel := range channels { - if err := channel.Close(); err != nil { - t.Fatalf("close channel %d/%d: %s", i+1, n, err) - } - } - t.Logf("created/closed %d channels OK", n) - } - - } -} - -func TestIntegrationMeaningfulChannelErrors(t *testing.T) { - c := integrationConnection(t, "pub") - if c != nil { - defer c.Close() - - ch, err := c.Channel() - if err != nil { - t.Fatalf("Could not create channel") - } - - queue := "test.integration.channel.error" - - _, err = ch.QueueDeclare(queue, false, true, false, false, nil) - if err != nil { - t.Fatalf("Could not declare") - } - - _, err = ch.QueueDeclare(queue, true, false, false, false, nil) - if err == nil { - t.Fatalf("Expected error, got nil") - } - - e, ok := err.(*Error) - if !ok { - t.Fatalf("Expected type Error response, got %T", err) - } - - if e.Code != PreconditionFailed { - t.Fatalf("Expected PreconditionFailed, got: %+v", e) - } - - _, err = ch.QueueDeclare(queue, false, true, false, false, nil) - if err != ErrClosed { - t.Fatalf("Expected channel to be closed, got: %T", err) - } - } -} - -// https://github.com/streadway/amqp/issues/6 -func TestIntegrationNonBlockingClose(t *testing.T) { - c := integrationConnection(t, "#6") - if c != nil { - defer c.Close() - - ch, err := c.Channel() - if err != nil { - t.Fatalf("Could not create channel") - } - - queue := "test.integration.blocking.close" - - _, err = ch.QueueDeclare(queue, false, true, false, false, nil) - if err != nil { - t.Fatalf("Could not declare") - } - - msgs, err := ch.Consume(queue, "", false, false, false, false, nil) - if err != nil { - t.Fatalf("Could not consume") - } - - // Simulate a consumer - go func() { - for _ = range msgs { - t.Logf("Oh my, received message on an empty queue") - } - }() - - succeed := make(chan bool) - - go func() { - if err = ch.Close(); err != nil { - t.Fatalf("Close produced an error when it shouldn't") - } - succeed <- true - }() - - select { - case <-succeed: - break - case <-time.After(1 * time.Second): - t.Fatalf("Close timed out after 1s") - } - } -} - -func TestIntegrationPublishConsume(t *testing.T) { - queue := "test.integration.publish.consume" - - c1 := integrationConnection(t, "pub") - c2 := integrationConnection(t, "sub") - - if c1 != nil && c2 != nil { - defer c1.Close() - defer c2.Close() - - pub, _ := c1.Channel() - sub, _ := c2.Channel() - - pub.QueueDeclare(queue, false, true, false, false, nil) - sub.QueueDeclare(queue, false, true, false, false, nil) - defer pub.QueueDelete(queue, false, false, false) - - messages, _ := sub.Consume(queue, "", false, false, false, false, nil) - - pub.Publish("", queue, false, false, Publishing{Body: []byte("pub 1")}) - pub.Publish("", queue, false, false, Publishing{Body: []byte("pub 2")}) - pub.Publish("", queue, false, false, Publishing{Body: []byte("pub 3")}) - - assertConsumeBody(t, messages, []byte("pub 1")) - assertConsumeBody(t, messages, []byte("pub 2")) - assertConsumeBody(t, messages, []byte("pub 3")) - } -} - -func TestIntegrationConsumeFlow(t *testing.T) { - queue := "test.integration.consumer-flow" - - c1 := integrationConnection(t, "pub-flow") - c2 := integrationConnection(t, "sub-flow") - - if c1 != nil && c2 != nil { - defer c1.Close() - defer c2.Close() - - pub, _ := c1.Channel() - sub, _ := c2.Channel() - - pub.QueueDeclare(queue, false, true, false, false, nil) - sub.QueueDeclare(queue, false, true, false, false, nil) - defer pub.QueueDelete(queue, false, false, false) - - sub.Qos(1, 0, false) - - messages, _ := sub.Consume(queue, "", false, false, false, false, nil) - - pub.Publish("", queue, false, false, Publishing{Body: []byte("pub 1")}) - pub.Publish("", queue, false, false, Publishing{Body: []byte("pub 2")}) - - msg := assertConsumeBody(t, messages, []byte("pub 1")) - - if err := sub.Flow(false); err.(*Error).Code == NotImplemented { - t.Log("flow control is not supported on this version of rabbitmq") - return - } - - msg.Ack(false) - - select { - case <-messages: - t.Fatalf("message was delivered when flow was not active") - default: - } - - sub.Flow(true) - - msg = assertConsumeBody(t, messages, []byte("pub 2")) - msg.Ack(false) - } -} - -func TestIntegrationRecoverNotImplemented(t *testing.T) { - queue := "test.recover" - - if c, ch := integrationQueue(t, queue); c != nil { - if product, ok := c.Properties["product"]; ok && product.(string) == "RabbitMQ" { - defer c.Close() - - err := ch.Recover(false) - - if ex, ok := err.(*Error); !ok || ex.Code != 540 { - t.Fatalf("Expected NOT IMPLEMENTED got: %v", ex) - } - } - } -} - -// This test is driven by a private API to simulate the server sending a channelFlow message -func TestIntegrationPublishFlow(t *testing.T) { - // TODO - no idea how to test without affecting the server or mucking internal APIs - // i'd like to make sure the RW lock can be held by multiple publisher threads - // and that multiple channelFlow messages do not block the dispatch thread -} - -func TestIntegrationConsumeCancel(t *testing.T) { - queue := "test.integration.consume-cancel" - - c := integrationConnection(t, "pub") - - if c != nil { - defer c.Close() - - ch, _ := c.Channel() - - ch.QueueDeclare(queue, false, true, false, false, nil) - defer ch.QueueDelete(queue, false, false, false) - - messages, _ := ch.Consume(queue, "integration-tag", false, false, false, false, nil) - - ch.Publish("", queue, false, false, Publishing{Body: []byte("1")}) - - assertConsumeBody(t, messages, []byte("1")) - - err := ch.Cancel("integration-tag", false) - if err != nil { - t.Fatalf("error cancelling the consumer: %v", err) - } - - ch.Publish("", queue, false, false, Publishing{Body: []byte("2")}) - - select { - case <-time.After(100 * time.Millisecond): - t.Fatalf("Timeout on Close") - case _, ok := <-messages: - if ok { - t.Fatalf("Extra message on consumer when consumer should have been closed") - } - } - } -} - -func (c *Connection) Generate(r *rand.Rand, _ int) reflect.Value { - urlStr := os.Getenv("AMQP_URL") - if urlStr == "" { - return reflect.ValueOf(nil) - } - - conn, err := Dial(urlStr) - if err != nil { - return reflect.ValueOf(nil) - } - - return reflect.ValueOf(conn) -} - -func (c Publishing) Generate(r *rand.Rand, _ int) reflect.Value { - var ok bool - var t reflect.Value - - p := Publishing{} - //p.DeliveryMode = uint8(r.Intn(3)) - //p.Priority = uint8(r.Intn(8)) - - if r.Intn(2) > 0 { - p.ContentType = "application/octet-stream" - } - - if r.Intn(2) > 0 { - p.ContentEncoding = "gzip" - } - - if r.Intn(2) > 0 { - p.CorrelationId = fmt.Sprintf("%d", r.Int()) - } - - if r.Intn(2) > 0 { - p.ReplyTo = fmt.Sprintf("%d", r.Int()) - } - - if r.Intn(2) > 0 { - p.MessageId = fmt.Sprintf("%d", r.Int()) - } - - if r.Intn(2) > 0 { - p.Type = fmt.Sprintf("%d", r.Int()) - } - - if r.Intn(2) > 0 { - p.AppId = fmt.Sprintf("%d", r.Int()) - } - - if r.Intn(2) > 0 { - p.Timestamp = time.Unix(r.Int63(), r.Int63()) - } - - if t, ok = quick.Value(reflect.TypeOf(p.Body), r); ok { - p.Body = t.Bytes() - } - - return reflect.ValueOf(p) -} - -func TestQuickPublishOnly(t *testing.T) { - if c := integrationConnection(t, "quick"); c != nil { - defer c.Close() - pub, err := c.Channel() - queue := "test-publish" - - if _, err = pub.QueueDeclare(queue, false, true, false, false, nil); err != nil { - t.Errorf("Failed to declare: %s", err) - return - } - - defer pub.QueueDelete(queue, false, false, false) - - quick.Check(func(msg Publishing) bool { - return pub.Publish("", queue, false, false, msg) == nil - }, nil) - } -} - -func TestPublishEmptyBody(t *testing.T) { - c := integrationConnection(t, "empty") - if c != nil { - defer c.Close() - - ch, err := c.Channel() - if err != nil { - t.Errorf("Failed to create channel") - return - } - - queue := "test-TestPublishEmptyBody" - - if _, err := ch.QueueDeclare(queue, false, true, false, false, nil); err != nil { - t.Fatalf("Could not declare") - } - - messages, err := ch.Consume(queue, "", false, false, false, false, nil) - if err != nil { - t.Fatalf("Could not consume") - } - - err = ch.Publish("", queue, false, false, Publishing{}) - if err != nil { - t.Fatalf("Could not publish") - } - - select { - case msg := <-messages: - if len(msg.Body) != 0 { - t.Errorf("Received non empty body") - } - case <-time.After(200 * time.Millisecond): - t.Errorf("Timeout on receive") - } - } -} - -func TestPublishEmptyBodyWithHeadersIssue67(t *testing.T) { - c := integrationConnection(t, "issue67") - if c != nil { - defer c.Close() - - ch, err := c.Channel() - if err != nil { - t.Errorf("Failed to create channel") - return - } - - queue := "test-TestPublishEmptyBodyWithHeaders" - - if _, err := ch.QueueDeclare(queue, false, true, false, false, nil); err != nil { - t.Fatalf("Could not declare") - } - - messages, err := ch.Consume(queue, "", false, false, false, false, nil) - if err != nil { - t.Fatalf("Could not consume") - } - - headers := Table{ - "ham": "spam", - } - - err = ch.Publish("", queue, false, false, Publishing{Headers: headers}) - if err != nil { - t.Fatalf("Could not publish") - } - - select { - case msg := <-messages: - if msg.Headers["ham"] == nil { - t.Fatalf("Headers aren't sent") - } - if msg.Headers["ham"] != "spam" { - t.Fatalf("Headers are wrong") - } - case <-time.After(200 * time.Millisecond): - t.Errorf("Timeout on receive") - } - } -} - -func TestQuickPublishConsumeOnly(t *testing.T) { - c1 := integrationConnection(t, "quick-pub") - c2 := integrationConnection(t, "quick-sub") - - if c1 != nil && c2 != nil { - defer c1.Close() - defer c2.Close() - - pub, err := c1.Channel() - sub, err := c2.Channel() - - queue := "TestPublishConsumeOnly" - - if _, err = pub.QueueDeclare(queue, false, true, false, false, nil); err != nil { - t.Errorf("Failed to declare: %s", err) - return - } - - if _, err = sub.QueueDeclare(queue, false, true, false, false, nil); err != nil { - t.Errorf("Failed to declare: %s", err) - return - } - - defer sub.QueueDelete(queue, false, false, false) - - ch, err := sub.Consume(queue, "", false, false, false, false, nil) - if err != nil { - t.Errorf("Could not sub: %s", err) - } - - quick.CheckEqual( - func(msg Publishing) []byte { - empty := Publishing{Body: msg.Body} - if pub.Publish("", queue, false, false, empty) != nil { - return []byte{'X'} - } - return msg.Body - }, - func(msg Publishing) []byte { - out := <-ch - out.Ack(false) - return out.Body - }, - nil) - } -} - -func TestQuickPublishConsumeBigBody(t *testing.T) { - c1 := integrationConnection(t, "big-pub") - c2 := integrationConnection(t, "big-sub") - - if c1 != nil && c2 != nil { - defer c1.Close() - defer c2.Close() - - pub, err := c1.Channel() - sub, err := c2.Channel() - - queue := "test-pubsub" - - if _, err = sub.QueueDeclare(queue, false, true, false, false, nil); err != nil { - t.Errorf("Failed to declare: %s", err) - return - } - - ch, err := sub.Consume(queue, "", false, false, false, false, nil) - if err != nil { - t.Errorf("Could not sub: %s", err) - } - - fixture := Publishing{ - Body: make([]byte, 1e4+1000), - } - - if _, err = pub.QueueDeclare(queue, false, true, false, false, nil); err != nil { - t.Errorf("Failed to declare: %s", err) - return - } - - err = pub.Publish("", queue, false, false, fixture) - if err != nil { - t.Errorf("Could not publish big body") - } - - select { - case msg := <-ch: - if bytes.Compare(msg.Body, fixture.Body) != 0 { - t.Errorf("Consumed big body didn't match") - } - case <-time.After(200 * time.Millisecond): - t.Errorf("Timeout on receive") - } - } -} - -func TestIntegrationGetOk(t *testing.T) { - if c := integrationConnection(t, "getok"); c != nil { - defer c.Close() - - queue := "test.get-ok" - ch, _ := c.Channel() - - ch.QueueDeclare(queue, false, true, false, false, nil) - ch.Publish("", queue, false, false, Publishing{Body: []byte("ok")}) - - msg, ok, err := ch.Get(queue, false) - - if err != nil { - t.Fatalf("Failed get: %v", err) - } - - if !ok { - t.Fatalf("Get on a queued message did not find the message") - } - - if string(msg.Body) != "ok" { - t.Fatalf("Get did not get the correct message") - } - } -} - -func TestIntegrationGetEmpty(t *testing.T) { - if c := integrationConnection(t, "getok"); c != nil { - defer c.Close() - - queue := "test.get-ok" - ch, _ := c.Channel() - - ch.QueueDeclare(queue, false, true, false, false, nil) - - _, ok, err := ch.Get(queue, false) - - if err != nil { - t.Fatalf("Failed get: %v", err) - } - - if !ok { - t.Fatalf("Get on a queued message retrieved a message when it shouldn't have") - } - } -} - -func TestIntegrationTxCommit(t *testing.T) { - if c := integrationConnection(t, "txcommit"); c != nil { - defer c.Close() - - queue := "test.tx.commit" - ch, _ := c.Channel() - - ch.QueueDeclare(queue, false, true, false, false, nil) - - if err := ch.Tx(); err != nil { - t.Fatalf("tx.select failed") - } - - ch.Publish("", queue, false, false, Publishing{Body: []byte("ok")}) - - if err := ch.TxCommit(); err != nil { - t.Fatalf("tx.commit failed") - } - - msg, ok, err := ch.Get(queue, false) - - if err != nil || !ok { - t.Fatalf("Failed get: %v", err) - } - - if string(msg.Body) != "ok" { - t.Fatalf("Get did not get the correct message from the transaction") - } - } -} - -func TestIntegrationTxRollback(t *testing.T) { - if c := integrationConnection(t, "txrollback"); c != nil { - defer c.Close() - - queue := "test.tx.rollback" - ch, _ := c.Channel() - - ch.QueueDeclare(queue, false, true, false, false, nil) - - if err := ch.Tx(); err != nil { - t.Fatalf("tx.select failed") - } - - ch.Publish("", queue, false, false, Publishing{Body: []byte("ok")}) - - if err := ch.TxRollback(); err != nil { - t.Fatalf("tx.rollback failed") - } - - _, ok, err := ch.Get(queue, false) - - if err != nil { - t.Fatalf("Failed get: %v", err) - } - - if ok { - t.Fatalf("message was published when it should have been rolled back") - } - } -} - -func TestIntegrationReturn(t *testing.T) { - if c, ch := integrationQueue(t, "return"); c != nil { - defer c.Close() - - ret := make(chan Return, 1) - - ch.NotifyReturn(ret) - - // mandatory publish to an exchange without a binding should be returned - ch.Publish("", "return-without-binding", true, false, Publishing{Body: []byte("mandatory")}) - - select { - case res := <-ret: - if string(res.Body) != "mandatory" { - t.Fatalf("expected return of the same message") - } - - if res.ReplyCode != NoRoute { - t.Fatalf("expected no consumers reply code on the Return result, got: %v", res.ReplyCode) - } - - case <-time.After(200 * time.Millisecond): - t.Fatalf("no return was received within 200ms") - } - } -} - -func TestIntegrationCancel(t *testing.T) { - queue := "cancel" - consumerTag := "test.cancel" - - if c, ch := integrationQueue(t, queue); c != nil { - defer c.Close() - - cancels := ch.NotifyCancel(make(chan string, 1)) - - go func() { - if _, err := ch.Consume(queue, consumerTag, false, false, false, false, nil); err != nil { - t.Fatalf("cannot consume from %q to test NotifyCancel: %v", queue, err) - } - if _, err := ch.QueueDelete(queue, false, false, false); err != nil { - t.Fatalf("cannot delete integration queue: %v", err) - } - }() - - select { - case tag := <-cancels: - if want, got := consumerTag, tag; want != got { - t.Fatalf("expected to be notified of deleted queue with consumer tag, got: %q", got) - } - case <-time.After(200 * time.Millisecond): - t.Fatalf("expected to be notified of deleted queue with 200ms") - } - } -} - -func TestIntegrationConfirm(t *testing.T) { - if c, ch := integrationQueue(t, "confirm"); c != nil { - defer c.Close() - - ack, nack := make(chan uint64, 1), make(chan uint64, 1) - - ch.NotifyConfirm(ack, nack) - - if err := ch.Confirm(false); err != nil { - t.Fatalf("could not confirm") - } - - ch.Publish("", "confirm", false, false, Publishing{Body: []byte("confirm")}) - - select { - case tag := <-ack: - if tag != 1 { - t.Fatalf("expected ack starting with delivery tag of 1") - } - case <-time.After(200 * time.Millisecond): - t.Fatalf("no ack was received within 200ms") - } - } -} - -// https://github.com/streadway/amqp/issues/61 -func TestRoundTripAllFieldValueTypes61(t *testing.T) { - if conn := integrationConnection(t, "issue61"); conn != nil { - defer conn.Close() - timestamp := time.Unix(100000000, 0) - - headers := Table{ - "A": []interface{}{ - []interface{}{"nested array", int32(3)}, - Decimal{2, 1}, - Table{"S": "nested table in array"}, - int32(2 << 20), - string("array string"), - timestamp, - nil, - byte(2), - float64(2.64), - float32(2.32), - int64(2 << 60), - int16(2 << 10), - bool(true), - []byte{'b', '2'}, - }, - "D": Decimal{1, 1}, - "F": Table{"S": "nested table in table"}, - "I": int32(1 << 20), - "S": string("string"), - "T": timestamp, - "V": nil, - "b": byte(1), - "d": float64(1.64), - "f": float32(1.32), - "l": int64(1 << 60), - "s": int16(1 << 10), - "t": bool(true), - "x": []byte{'b', '1'}, - } - - queue := "test.issue61-roundtrip" - ch, _ := conn.Channel() - - if _, err := ch.QueueDeclare(queue, false, true, false, false, nil); err != nil { - t.Fatalf("Could not declare") - } - - msgs, err := ch.Consume(queue, "", false, false, false, false, nil) - if err != nil { - t.Fatalf("Could not consume") - } - - err = ch.Publish("", queue, false, false, Publishing{Body: []byte("ignored"), Headers: headers}) - if err != nil { - t.Fatalf("Could not publish: %v", err) - } - - msg, ok := <-msgs - - if !ok { - t.Fatalf("Channel closed prematurely likely due to publish exception") - } - - for k, v := range headers { - if !reflect.DeepEqual(v, msg.Headers[k]) { - t.Errorf("Round trip header not the same for key %q: expected: %#v, got %#v", k, v, msg.Headers[k]) - } - } - } -} - -// Declares a queue with the x-message-ttl extension to exercise integer -// serialization. -// -// Relates to https://github.com/streadway/amqp/issues/60 -// -func TestDeclareArgsXMessageTTL(t *testing.T) { - if conn := integrationConnection(t, "declareTTL"); conn != nil { - defer conn.Close() - - ch, _ := conn.Channel() - args := Table{"x-message-ttl": int32(9000000)} - - // should not drop the connection - if _, err := ch.QueueDeclare("declareWithTTL", false, true, false, false, args); err != nil { - t.Fatalf("cannot declare with TTL: got: %v", err) - } - } -} - -// Sets up the topology where rejected messages will be forwarded -// to a fanout exchange, with a single queue bound. -// -// Relates to https://github.com/streadway/amqp/issues/56 -// -func TestDeclareArgsRejectToDeadLetterQueue(t *testing.T) { - if conn := integrationConnection(t, "declareArgs"); conn != nil { - defer conn.Close() - - ex, q := "declareArgs", "declareArgs-deliveries" - dlex, dlq := ex+"-dead-letter", q+"-dead-letter" - - ch, _ := conn.Channel() - - if err := ch.ExchangeDeclare(ex, "fanout", false, true, false, false, nil); err != nil { - t.Fatalf("cannot declare %v: got: %v", ex, err) - } - - if err := ch.ExchangeDeclare(dlex, "fanout", false, true, false, false, nil); err != nil { - t.Fatalf("cannot declare %v: got: %v", dlex, err) - } - - if _, err := ch.QueueDeclare(dlq, false, true, false, false, nil); err != nil { - t.Fatalf("cannot declare %v: got: %v", dlq, err) - } - - if err := ch.QueueBind(dlq, "#", dlex, false, nil); err != nil { - t.Fatalf("cannot bind %v to %v: got: %v", dlq, dlex, err) - } - - if _, err := ch.QueueDeclare(q, false, true, false, false, Table{ - "x-dead-letter-exchange": dlex, - }); err != nil { - t.Fatalf("cannot declare %v with dlq %v: got: %v", q, dlex, err) - } - - if err := ch.QueueBind(q, "#", ex, false, nil); err != nil { - t.Fatalf("cannot bind %v: got: %v", ex, err) - } - - fails, err := ch.Consume(q, "", false, false, false, false, nil) - if err != nil { - t.Fatalf("cannot consume %v: got: %v", q, err) - } - - // Reject everything consumed - go func() { - for d := range fails { - d.Reject(false) - } - }() - - // Publish the 'poison' - if err := ch.Publish(ex, q, true, false, Publishing{Body: []byte("ignored")}); err != nil { - t.Fatalf("publishing failed") - } - - // spin-get until message arrives on the dead-letter queue with a - // synchronous parse to exercise the array field (x-death) set by the - // server relating to issue-56 - for i := 0; i < 10; i++ { - d, got, err := ch.Get(dlq, false) - if !got && err == nil { - continue - } else if err != nil { - t.Fatalf("expected success in parsing reject, got: %v", err) - } else { - // pass if we've parsed an array - if v, ok := d.Headers["x-death"]; ok { - if _, ok := v.([]interface{}); ok { - return - } - } - t.Fatalf("array field x-death expected in the headers, got: %v (%T)", d.Headers, d.Headers["x-death"]) - } - } - - t.Fatalf("expectd dead-letter after 10 get attempts") - } -} - -// https://github.com/streadway/amqp/issues/48 -func TestDeadlockConsumerIssue48(t *testing.T) { - if conn := integrationConnection(t, "issue48"); conn != nil { - defer conn.Close() - - deadline := make(chan bool) - go func() { - select { - case <-time.After(5 * time.Second): - panic("expected to receive 2 deliveries while in an RPC, got a deadlock") - case <-deadline: - // pass - } - }() - - ch, err := conn.Channel() - if err != nil { - t.Fatalf("got error on channel.open: %v", err) - } - - queue := "test-issue48" - - if _, err := ch.QueueDeclare(queue, false, true, false, false, nil); err != nil { - t.Fatalf("expected to declare a queue: %v", err) - } - - if err := ch.Confirm(false); err != nil { - t.Fatalf("got error on confirm: %v", err) - } - - ack, nack := make(chan uint64, 2), make(chan uint64, 2) - ch.NotifyConfirm(ack, nack) - - for i := 0; i < cap(ack); i++ { - // Fill the queue with some new or remaining publishings - ch.Publish("", queue, false, false, Publishing{Body: []byte("")}) - } - - for i := 0; i < cap(ack); i++ { - // Wait for them to land on the queue so they'll be delivered on consume - <-ack - } - - // Consuming should send them all on the wire - msgs, err := ch.Consume(queue, "", false, false, false, false, nil) - if err != nil { - t.Fatalf("got error on consume: %v", err) - } - - // We pop one off the chan, the other is on the wire - <-msgs - - // Opening a new channel (any RPC) while another delivery is on the wire - if _, err := conn.Channel(); err != nil { - t.Fatalf("got error on consume: %v", err) - } - - // We pop the next off the chan - <-msgs - - deadline <- true - } -} - -// https://github.com/streadway/amqp/issues/46 -func TestRepeatedChannelExceptionWithPublishAndMaxProcsIssue46(t *testing.T) { - conn := integrationConnection(t, "issue46") - if conn != nil { - for i := 0; i < 100; i++ { - ch, err := conn.Channel() - if err != nil { - t.Fatalf("expected error only on publish, got error on channel.open: %v", err) - } - - for j := 0; j < 10; j++ { - err = ch.Publish("not-existing-exchange", "some-key", false, false, Publishing{Body: []byte("some-data")}) - if err, ok := err.(Error); ok { - if err.Code != 504 { - t.Fatalf("expected channel only exception, got: %v", err) - } - } - } - } - } -} - -// https://github.com/streadway/amqp/issues/43 -func TestChannelExceptionWithCloseIssue43(t *testing.T) { - conn := integrationConnection(t, "issue43") - if conn != nil { - go func() { - for err := range conn.NotifyClose(make(chan *Error)) { - t.Log(err.Error()) - } - }() - - c1, err := conn.Channel() - if err != nil { - panic(err) - } - - go func() { - for err := range c1.NotifyClose(make(chan *Error)) { - t.Log("Channel1 Close: " + err.Error()) - } - }() - - c2, err := conn.Channel() - if err != nil { - panic(err) - } - - go func() { - for err := range c2.NotifyClose(make(chan *Error)) { - t.Log("Channel2 Close: " + err.Error()) - } - }() - - // Cause an asynchronous channel exception causing the server - // to send a "channel.close" method either before or after the next - // asynchronous method. - err = c1.Publish("nonexisting-exchange", "", false, false, Publishing{}) - if err != nil { - panic(err) - } - - // Receive or send the channel close method, the channel shuts down - // but this expects a channel.close-ok to be received. - c1.Close() - - // This ensures that the 2nd channel is unaffected by the channel exception - // on channel 1. - err = c2.ExchangeDeclare("test-channel-still-exists", "direct", false, true, false, false, nil) - if err != nil { - panic(err) - } - } -} - -// https://github.com/streadway/amqp/issues/7 -func TestCorruptedMessageIssue7(t *testing.T) { - messageCount := 1024 - - c1 := integrationConnection(t, "") - c2 := integrationConnection(t, "") - - if c1 != nil && c2 != nil { - defer c1.Close() - defer c2.Close() - - pub, err := c1.Channel() - if err != nil { - t.Fatalf("Cannot create Channel") - } - - sub, err := c2.Channel() - if err != nil { - t.Fatalf("Cannot create Channel") - } - - queue := "test-corrupted-message-regression" - - if _, err := pub.QueueDeclare(queue, false, true, false, false, nil); err != nil { - t.Fatalf("Cannot declare") - } - - if _, err := sub.QueueDeclare(queue, false, true, false, false, nil); err != nil { - t.Fatalf("Cannot declare") - } - - msgs, err := sub.Consume(queue, "", false, false, false, false, nil) - if err != nil { - t.Fatalf("Cannot consume") - } - - for i := 0; i < messageCount; i++ { - err := pub.Publish("", queue, false, false, Publishing{ - Body: generateCrc32Random(7 * i), - }) - - if err != nil { - t.Fatalf("Failed to publish") - } - } - - for i := 0; i < messageCount; i++ { - select { - case msg := <-msgs: - assertMessageCrc32(t, msg.Body, fmt.Sprintf("missed match at %d", i)) - case <-time.After(200 * time.Millisecond): - t.Fatalf("Timeout on recv") - } - } - } -} - -func TestExchangeDeclarePrecondition(t *testing.T) { - c1 := integrationConnection(t, "exchange-double-declare") - c2 := integrationConnection(t, "exchange-double-declare-cleanup") - if c1 != nil && c2 != nil { - defer c1.Close() - defer c2.Close() - - ch, err := c1.Channel() - if err != nil { - t.Fatalf("Create channel") - } - - exchange := "test-mismatched-redeclare" - - err = ch.ExchangeDeclare( - exchange, - "direct", // exchangeType - false, // durable - true, // auto-delete - false, // internal - false, // noWait - nil, // arguments - ) - if err != nil { - t.Fatalf("Could not initially declare exchange") - } - - err = ch.ExchangeDeclare( - exchange, - "direct", - true, // different durability - true, - false, - false, - nil, - ) - - if err == nil { - t.Fatalf("Expected to fail a redeclare with different durability, didn't receive an error") - } - - if err, ok := err.(Error); ok { - if err.Code != PreconditionFailed { - t.Fatalf("Expected precondition error") - } - if !err.Recover { - t.Fatalf("Expected to be able to recover") - } - } - - ch2, _ := c2.Channel() - if err = ch2.ExchangeDelete(exchange, false, false); err != nil { - t.Fatalf("Could not delete exchange: %v", err) - } - } -} - -func TestRabbitMQQueueTTLGet(t *testing.T) { - if c := integrationRabbitMQ(t, "ttl"); c != nil { - defer c.Close() - - queue := "test.rabbitmq-message-ttl" - channel, err := c.Channel() - if err != nil { - t.Fatalf("channel: %v", err) - } - - if _, err = channel.QueueDeclare( - queue, - false, - true, - false, - false, - Table{"x-message-ttl": int32(100)}, // in ms - ); err != nil { - t.Fatalf("queue declare: %s", err) - } - - channel.Publish("", queue, false, false, Publishing{Body: []byte("ttl")}) - - time.Sleep(200 * time.Millisecond) - - _, ok, err := channel.Get(queue, false) - - if ok { - t.Fatalf("Expected the message to expire in 100ms, it didn't expire after 200ms") - } - - if err != nil { - t.Fatalf("Failed to get on ttl queue") - } - } -} - -func TestRabbitMQQueueNackMultipleRequeue(t *testing.T) { - if c := integrationRabbitMQ(t, "nack"); c != nil { - defer c.Close() - - if c.isCapable("basic.nack") { - queue := "test.rabbitmq-basic-nack" - channel, err := c.Channel() - if err != nil { - t.Fatalf("channel: %v", err) - } - - if _, err = channel.QueueDeclare(queue, false, true, false, false, nil); err != nil { - t.Fatalf("queue declare: %s", err) - } - - channel.Publish("", queue, false, false, Publishing{Body: []byte("1")}) - channel.Publish("", queue, false, false, Publishing{Body: []byte("2")}) - - m1, ok, err := channel.Get(queue, false) - if !ok || err != nil || m1.Body[0] != '1' { - t.Fatalf("could not get message %v", m1) - } - - m2, ok, err := channel.Get(queue, false) - if !ok || err != nil || m2.Body[0] != '2' { - t.Fatalf("could not get message %v", m2) - } - - m2.Nack(true, true) - - m1, ok, err = channel.Get(queue, false) - if !ok || err != nil || m1.Body[0] != '1' { - t.Fatalf("could not get message %v", m1) - } - - m2, ok, err = channel.Get(queue, false) - if !ok || err != nil || m2.Body[0] != '2' { - t.Fatalf("could not get message %v", m2) - } - } - } -} - -/* - * Support for integration tests - */ - -func integrationURLFromEnv() string { - url := os.Getenv("AMQP_URL") - if url == "" { - url = "amqp://" - } - return url -} - -func loggedConnection(t *testing.T, conn *Connection, name string) *Connection { - if name != "" { - conn.conn = &logIO{t, name, conn.conn} - } - return conn -} - -// Returns a conneciton to the AMQP if the AMQP_URL environment -// variable is set and a connnection can be established. -func integrationConnection(t *testing.T, name string) *Connection { - conn, err := Dial(integrationURLFromEnv()) - if err != nil { - t.Errorf("dial integration server: %s", err) - return nil - } - return loggedConnection(t, conn, name) -} - -// Returns a connection, channel and delcares a queue when the AMQP_URL is in the environment -func integrationQueue(t *testing.T, name string) (*Connection, *Channel) { - if conn := integrationConnection(t, name); conn != nil { - if channel, err := conn.Channel(); err == nil { - if _, err = channel.QueueDeclare(name, false, true, false, false, nil); err == nil { - return conn, channel - } - } - } - return nil, nil -} - -// Delegates to integrationConnection and only returns a connection if the -// product is RabbitMQ -func integrationRabbitMQ(t *testing.T, name string) *Connection { - if conn := integrationConnection(t, "connect"); conn != nil { - if server, ok := conn.Properties["product"]; ok && server == "RabbitMQ" { - return conn - } - } - - return nil -} - -func assertConsumeBody(t *testing.T, messages <-chan Delivery, want []byte) (msg *Delivery) { - select { - case got := <-messages: - if bytes.Compare(want, got.Body) != 0 { - t.Fatalf("Message body does not match want: %v, got: %v, for: %+v", want, got.Body, got) - } - msg = &got - case <-time.After(200 * time.Millisecond): - t.Fatalf("Timeout waiting for %v", want) - } - - return msg -} - -// Pulls out the CRC and verifies the remaining content against the CRC -func assertMessageCrc32(t *testing.T, msg []byte, assert string) { - size := binary.BigEndian.Uint32(msg[:4]) - - crc := crc32.NewIEEE() - crc.Write(msg[8:]) - - if binary.BigEndian.Uint32(msg[4:8]) != crc.Sum32() { - t.Fatalf("Message does not match CRC: %s", assert) - } - - if int(size) != len(msg)-8 { - t.Fatalf("Message does not match size, should=%d, is=%d: %s", size, len(msg)-8, assert) - } -} - -// Creates a random body size with a leading 32-bit CRC in network byte order -// that verifies the remaining slice -func generateCrc32Random(size int) []byte { - msg := make([]byte, size+8) - if _, err := io.ReadFull(devrand.Reader, msg); err != nil { - panic(err) - } - - crc := crc32.NewIEEE() - crc.Write(msg[8:]) - - binary.BigEndian.PutUint32(msg[0:4], uint32(size)) - binary.BigEndian.PutUint32(msg[4:8], crc.Sum32()) - - return msg -} diff --git a/vendor/github.com/streadway/amqp/read.go b/vendor/github.com/streadway/amqp/read.go deleted file mode 100644 index 2ef7a9e47d4..00000000000 --- a/vendor/github.com/streadway/amqp/read.go +++ /dev/null @@ -1,444 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -package amqp - -import ( - "bytes" - "encoding/binary" - "io" - "time" -) - -/* -Reads a frame from an input stream and returns an interface that can be cast into -one of the following: - - methodFrame - PropertiesFrame - bodyFrame - heartbeatFrame - -2.3.5 frame Details - -All frames consist of a header (7 octets), a payload of arbitrary size, and a -'frame-end' octet that detects malformed frames: - - 0 1 3 7 size+7 size+8 - +------+---------+-------------+ +------------+ +-----------+ - | type | channel | size | | payload | | frame-end | - +------+---------+-------------+ +------------+ +-----------+ - octet short long size octets octet - -To read a frame, we: - 1. Read the header and check the frame type and channel. - 2. Depending on the frame type, we read the payload and process it. - 3. Read the frame end octet. - -In realistic implementations where performance is a concern, we would use -“read-ahead buffering” or - -“gathering reads” to avoid doing three separate system calls to read a frame. -*/ -func (me *reader) ReadFrame() (frame frame, err error) { - var scratch [7]byte - - if _, err = io.ReadFull(me.r, scratch[:7]); err != nil { - return - } - - typ := uint8(scratch[0]) - channel := binary.BigEndian.Uint16(scratch[1:3]) - size := binary.BigEndian.Uint32(scratch[3:7]) - - switch typ { - case frameMethod: - if frame, err = me.parseMethodFrame(channel, size); err != nil { - return - } - - case frameHeader: - if frame, err = me.parseHeaderFrame(channel, size); err != nil { - return - } - - case frameBody: - if frame, err = me.parseBodyFrame(channel, size); err != nil { - return - } - - case frameHeartbeat: - if frame, err = me.parseHeartbeatFrame(channel, size); err != nil { - return - } - - default: - return nil, ErrFrame - } - - if _, err = io.ReadFull(me.r, scratch[:1]); err != nil { - return - } - - if scratch[0] != frameEnd { - return nil, ErrFrame - } - - return -} - -func readShortstr(r io.Reader) (v string, err error) { - var length uint8 - if err = binary.Read(r, binary.BigEndian, &length); err != nil { - return - } - - bytes := make([]byte, length) - if _, err = io.ReadFull(r, bytes); err != nil { - return - } - return string(bytes), nil -} - -func readLongstr(r io.Reader) (v string, err error) { - var length uint32 - if err = binary.Read(r, binary.BigEndian, &length); err != nil { - return - } - - bytes := make([]byte, length) - if _, err = io.ReadFull(r, bytes); err != nil { - return - } - return string(bytes), nil -} - -func readDecimal(r io.Reader) (v Decimal, err error) { - if err = binary.Read(r, binary.BigEndian, &v.Scale); err != nil { - return - } - if err = binary.Read(r, binary.BigEndian, &v.Value); err != nil { - return - } - return -} - -func readFloat32(r io.Reader) (v float32, err error) { - if err = binary.Read(r, binary.BigEndian, &v); err != nil { - return - } - return -} - -func readFloat64(r io.Reader) (v float64, err error) { - if err = binary.Read(r, binary.BigEndian, &v); err != nil { - return - } - return -} - -func readTimestamp(r io.Reader) (v time.Time, err error) { - var sec int64 - if err = binary.Read(r, binary.BigEndian, &sec); err != nil { - return - } - return time.Unix(sec, 0), nil -} - -/* -'A': []interface{} -'D': Decimal -'F': Table -'I': int32 -'S': string -'T': time.Time -'V': nil -'b': byte -'d': float64 -'f': float32 -'l': int64 -'s': int16 -'t': bool -'x': []byte -*/ -func readField(r io.Reader) (v interface{}, err error) { - var typ byte - if err = binary.Read(r, binary.BigEndian, &typ); err != nil { - return - } - - switch typ { - case 't': - var value uint8 - if err = binary.Read(r, binary.BigEndian, &value); err != nil { - return - } - return (value != 0), nil - - case 'b': - var value [1]byte - if _, err = io.ReadFull(r, value[0:1]); err != nil { - return - } - return value[0], nil - - case 's': - var value int16 - if err = binary.Read(r, binary.BigEndian, &value); err != nil { - return - } - return value, nil - - case 'I': - var value int32 - if err = binary.Read(r, binary.BigEndian, &value); err != nil { - return - } - return value, nil - - case 'l': - var value int64 - if err = binary.Read(r, binary.BigEndian, &value); err != nil { - return - } - return value, nil - - case 'f': - var value float32 - if err = binary.Read(r, binary.BigEndian, &value); err != nil { - return - } - return value, nil - - case 'd': - var value float64 - if err = binary.Read(r, binary.BigEndian, &value); err != nil { - return - } - return value, nil - - case 'D': - return readDecimal(r) - - case 'S': - return readLongstr(r) - - case 'A': - return readArray(r) - - case 'T': - return readTimestamp(r) - - case 'F': - return readTable(r) - - case 'x': - var len int32 - if err = binary.Read(r, binary.BigEndian, &len); err != nil { - return nil, err - } - - value := make([]byte, len) - if _, err = io.ReadFull(r, value); err != nil { - return nil, err - } - return value, err - - case 'V': - return nil, nil - } - - return nil, ErrSyntax -} - -/* - Field tables are long strings that contain packed name-value pairs. The - name-value pairs are encoded as short string defining the name, and octet - defining the values type and then the value itself. The valid field types for - tables are an extension of the native integer, bit, string, and timestamp - types, and are shown in the grammar. Multi-octet integer fields are always - held in network byte order. -*/ -func readTable(r io.Reader) (table Table, err error) { - var nested bytes.Buffer - var str string - - if str, err = readLongstr(r); err != nil { - return - } - - nested.Write([]byte(str)) - - table = make(Table) - - for nested.Len() > 0 { - var key string - var value interface{} - - if key, err = readShortstr(&nested); err != nil { - return - } - - if value, err = readField(&nested); err != nil { - return - } - - table[key] = value - } - - return -} - -func readArray(r io.Reader) ([]interface{}, error) { - var size uint32 - var err error - - if err = binary.Read(r, binary.BigEndian, &size); err != nil { - return nil, err - } - - lim := &io.LimitedReader{R: r, N: int64(size)} - arr := make([]interface{}, 0) - var field interface{} - - for { - if field, err = readField(lim); err != nil { - if err == io.EOF { - break - } - return nil, err - } - arr = append(arr, field) - } - - return arr, nil -} - -// Checks if this bit mask matches the flags bitset -func hasProperty(mask uint16, prop int) bool { - return int(mask)&prop > 0 -} - -func (me *reader) parseHeaderFrame(channel uint16, size uint32) (frame frame, err error) { - hf := &headerFrame{ - ChannelId: channel, - } - - if err = binary.Read(me.r, binary.BigEndian, &hf.ClassId); err != nil { - return - } - - if err = binary.Read(me.r, binary.BigEndian, &hf.weight); err != nil { - return - } - - if err = binary.Read(me.r, binary.BigEndian, &hf.Size); err != nil { - return - } - - var flags uint16 - - if err = binary.Read(me.r, binary.BigEndian, &flags); err != nil { - return - } - - if hasProperty(flags, flagContentType) { - if hf.Properties.ContentType, err = readShortstr(me.r); err != nil { - return - } - } - if hasProperty(flags, flagContentEncoding) { - if hf.Properties.ContentEncoding, err = readShortstr(me.r); err != nil { - return - } - } - if hasProperty(flags, flagHeaders) { - if hf.Properties.Headers, err = readTable(me.r); err != nil { - return - } - } - if hasProperty(flags, flagDeliveryMode) { - if err = binary.Read(me.r, binary.BigEndian, &hf.Properties.DeliveryMode); err != nil { - return - } - } - if hasProperty(flags, flagPriority) { - if err = binary.Read(me.r, binary.BigEndian, &hf.Properties.Priority); err != nil { - return - } - } - if hasProperty(flags, flagCorrelationId) { - if hf.Properties.CorrelationId, err = readShortstr(me.r); err != nil { - return - } - } - if hasProperty(flags, flagReplyTo) { - if hf.Properties.ReplyTo, err = readShortstr(me.r); err != nil { - return - } - } - if hasProperty(flags, flagExpiration) { - if hf.Properties.Expiration, err = readShortstr(me.r); err != nil { - return - } - } - if hasProperty(flags, flagMessageId) { - if hf.Properties.MessageId, err = readShortstr(me.r); err != nil { - return - } - } - if hasProperty(flags, flagTimestamp) { - if hf.Properties.Timestamp, err = readTimestamp(me.r); err != nil { - return - } - } - if hasProperty(flags, flagType) { - if hf.Properties.Type, err = readShortstr(me.r); err != nil { - return - } - } - if hasProperty(flags, flagUserId) { - if hf.Properties.UserId, err = readShortstr(me.r); err != nil { - return - } - } - if hasProperty(flags, flagAppId) { - if hf.Properties.AppId, err = readShortstr(me.r); err != nil { - return - } - } - if hasProperty(flags, flagReserved1) { - if hf.Properties.reserved1, err = readShortstr(me.r); err != nil { - return - } - } - - return hf, nil -} - -func (me *reader) parseBodyFrame(channel uint16, size uint32) (frame frame, err error) { - bf := &bodyFrame{ - ChannelId: channel, - Body: make([]byte, size), - } - - if _, err = io.ReadFull(me.r, bf.Body); err != nil { - return - } - - return bf, nil -} - -func (me *reader) parseHeartbeatFrame(channel uint16, size uint32) (frame frame, err error) { - hf := &heartbeatFrame{ - ChannelId: channel, - } - - if size > 0 { - panic("Heartbeats should not have a payload") - } - - return hf, nil -} diff --git a/vendor/github.com/streadway/amqp/reconnect_test.go b/vendor/github.com/streadway/amqp/reconnect_test.go deleted file mode 100644 index 5a06cb7aef4..00000000000 --- a/vendor/github.com/streadway/amqp/reconnect_test.go +++ /dev/null @@ -1,113 +0,0 @@ -package amqp_test - -import ( - "fmt" - "github.com/streadway/amqp" - "os" -) - -// Every connection should declare the topology they expect -func setup(url, queue string) (*amqp.Connection, *amqp.Channel, error) { - conn, err := amqp.Dial(url) - if err != nil { - return nil, nil, err - } - - ch, err := conn.Channel() - if err != nil { - return nil, nil, err - } - - if _, err := ch.QueueDeclare(queue, false, true, false, false, nil); err != nil { - return nil, nil, err - } - - return conn, ch, nil -} - -func consume(url, queue string) (*amqp.Connection, <-chan amqp.Delivery, error) { - conn, ch, err := setup(url, queue) - if err != nil { - return nil, nil, err - } - - // Indicate we only want 1 message to acknowledge at a time. - if err := ch.Qos(1, 0, false); err != nil { - return nil, nil, err - } - - // Exclusive consumer - deliveries, err := ch.Consume(queue, "", false, true, false, false, nil) - - return conn, deliveries, err -} - -func ExampleConnection_reconnect() { - if url := os.Getenv("AMQP_URL"); url != "" { - queue := "example.reconnect" - - // The connection/channel for publishing to interleave the ingress messages - // between reconnects, shares the same topology as the consumer. If we rather - // sent all messages up front, the first consumer would receive every message. - // We would rather show how the messages are not lost between reconnects. - _, pub, err := setup(url, queue) - if err != nil { - fmt.Println("err publisher setup:", err) - return - } - - // Purge the queue from the publisher side to establish initial state - if _, err := pub.QueuePurge(queue, false); err != nil { - fmt.Println("err purge:", err) - return - } - - // Reconnect simulation, should be for { ... } in production - for i := 1; i <= 3; i++ { - fmt.Println("connect") - - conn, deliveries, err := consume(url, queue) - if err != nil { - fmt.Println("err consume:", err) - return - } - - // Simulate a producer on a different connection showing that consumers - // continue where they were left off after each reconnect. - if err := pub.Publish("", queue, false, false, amqp.Publishing{ - Body: []byte(fmt.Sprintf("%d", i)), - }); err != nil { - fmt.Println("err publish:", err) - return - } - - // Simulates a consumer that when the range finishes, will setup a new - // session and begin ranging over the deliveries again. - for msg := range deliveries { - fmt.Println(string(msg.Body)) - msg.Ack(false) - - // Simulate an error like a server restart, loss of route or operator - // intervention that results in the connection terminating - go conn.Close() - } - } - } else { - // pass with expected output when not running in an integration - // environment. - fmt.Println("connect") - fmt.Println("1") - fmt.Println("connect") - fmt.Println("2") - fmt.Println("connect") - fmt.Println("3") - } - - // Output: - // connect - // 1 - // connect - // 2 - // connect - // 3 -} diff --git a/vendor/github.com/streadway/amqp/return.go b/vendor/github.com/streadway/amqp/return.go deleted file mode 100644 index dfebd635dd1..00000000000 --- a/vendor/github.com/streadway/amqp/return.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -package amqp - -import ( - "time" -) - -// Return captures a flattened struct of fields returned by the server when a -// Publishing is unable to be delivered either due to the `mandatory` flag set -// and no route found, or `immediate` flag set and no free consumer. -type Return struct { - ReplyCode uint16 // reason - ReplyText string // description - Exchange string // basic.publish exchange - RoutingKey string // basic.publish routing key - - // Properties - ContentType string // MIME content type - ContentEncoding string // MIME content encoding - Headers Table // Application or header exchange table - DeliveryMode uint8 // queue implemention use - non-persistent (1) or persistent (2) - Priority uint8 // queue implementation use - 0 to 9 - CorrelationId string // application use - correlation identifier - ReplyTo string // application use - address to to reply to (ex: RPC) - Expiration string // implementation use - message expiration spec - MessageId string // application use - message identifier - Timestamp time.Time // application use - message timestamp - Type string // application use - message type name - UserId string // application use - creating user id - AppId string // application use - creating application - - Body []byte -} - -func newReturn(msg basicReturn) *Return { - props, body := msg.getContent() - - return &Return{ - ReplyCode: msg.ReplyCode, - ReplyText: msg.ReplyText, - Exchange: msg.Exchange, - RoutingKey: msg.RoutingKey, - - Headers: props.Headers, - ContentType: props.ContentType, - ContentEncoding: props.ContentEncoding, - DeliveryMode: props.DeliveryMode, - Priority: props.Priority, - CorrelationId: props.CorrelationId, - ReplyTo: props.ReplyTo, - Expiration: props.Expiration, - MessageId: props.MessageId, - Timestamp: props.Timestamp, - Type: props.Type, - UserId: props.UserId, - AppId: props.AppId, - - Body: body, - } -} diff --git a/vendor/github.com/streadway/amqp/shared_test.go b/vendor/github.com/streadway/amqp/shared_test.go deleted file mode 100644 index 2e4715fa0eb..00000000000 --- a/vendor/github.com/streadway/amqp/shared_test.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -package amqp - -import ( - "encoding/hex" - "io" - "testing" -) - -type pipe struct { - r *io.PipeReader - w *io.PipeWriter -} - -func (p pipe) Read(b []byte) (int, error) { - return p.r.Read(b) -} - -func (p pipe) Write(b []byte) (int, error) { - return p.w.Write(b) -} - -func (p pipe) Close() error { - p.r.Close() - p.w.Close() - return nil -} - -type logIO struct { - t *testing.T - prefix string - proxy io.ReadWriteCloser -} - -func (me *logIO) Read(p []byte) (n int, err error) { - me.t.Logf("%s reading %d\n", me.prefix, len(p)) - n, err = me.proxy.Read(p) - if err != nil { - me.t.Logf("%s read %x: %v\n", me.prefix, p[0:n], err) - } else { - me.t.Logf("%s read:\n%s\n", me.prefix, hex.Dump(p[0:n])) - //fmt.Printf("%s read:\n%s\n", me.prefix, hex.Dump(p[0:n])) - } - return -} - -func (me *logIO) Write(p []byte) (n int, err error) { - me.t.Logf("%s writing %d\n", me.prefix, len(p)) - n, err = me.proxy.Write(p) - if err != nil { - me.t.Logf("%s write %d, %x: %v\n", me.prefix, len(p), p[0:n], err) - } else { - me.t.Logf("%s write %d:\n%s", me.prefix, len(p), hex.Dump(p[0:n])) - //fmt.Printf("%s write %d:\n%s", me.prefix, len(p), hex.Dump(p[0:n])) - } - return -} - -func (me *logIO) Close() (err error) { - err = me.proxy.Close() - if err != nil { - me.t.Logf("%s close : %v\n", me.prefix, err) - } else { - me.t.Logf("%s close\n", me.prefix, err) - } - return -} diff --git a/vendor/github.com/streadway/amqp/spec/amqp0-9-1.stripped.extended.xml b/vendor/github.com/streadway/amqp/spec/amqp0-9-1.stripped.extended.xml deleted file mode 100644 index fbddb93a3db..00000000000 --- a/vendor/github.com/streadway/amqp/spec/amqp0-9-1.stripped.extended.xml +++ /dev/null @@ -1,537 +0,0 @@ - - - - - - - - - - - - - - - - - Errata: Section 1.2 ought to define an exception 312 "No route", which used to - exist in 0-9 and is what RabbitMQ sends back with 'basic.return' when a - 'mandatory' message cannot be delivered to any queue. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vendor/github.com/streadway/amqp/spec/gen.go b/vendor/github.com/streadway/amqp/spec/gen.go deleted file mode 100644 index 1861b9ebbb3..00000000000 --- a/vendor/github.com/streadway/amqp/spec/gen.go +++ /dev/null @@ -1,536 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -// +build ignore - -package main - -import ( - "bytes" - "encoding/xml" - "errors" - "fmt" - "io/ioutil" - "log" - "os" - "regexp" - "strings" - "text/template" -) - -var ( - ErrUnknownType = errors.New("Unknown field type in gen") - ErrUnknownDomain = errors.New("Unknown domain type in gen") -) - -var amqpTypeToNative = map[string]string{ - "bit": "bool", - "octet": "byte", - "shortshort": "uint8", - "short": "uint16", - "long": "uint32", - "longlong": "uint64", - "timestamp": "time.Time", - "table": "Table", - "shortstr": "string", - "longstr": "string", -} - -type Rule struct { - Name string `xml:"name,attr"` - Docs []string `xml:"doc"` -} - -type Doc struct { - Type string `xml:"type,attr"` - Body string `xml:",innerxml"` -} - -type Chassis struct { - Name string `xml:"name,attr"` - Implement string `xml:"implement,attr"` -} - -type Assert struct { - Check string `xml:"check,attr"` - Value string `xml:"value,attr"` - Method string `xml:"method,attr"` -} - -type Field struct { - Name string `xml:"name,attr"` - Domain string `xml:"domain,attr"` - Type string `xml:"type,attr"` - Label string `xml:"label,attr"` - Reserved bool `xml:"reserved,attr"` - Docs []Doc `xml:"doc"` - Asserts []Assert `xml:"assert"` -} - -type Response struct { - Name string `xml:"name,attr"` -} - -type Method struct { - Name string `xml:"name,attr"` - Response Response `xml:"response"` - Synchronous bool `xml:"synchronous,attr"` - Content bool `xml:"content,attr"` - Index string `xml:"index,attr"` - Label string `xml:"label,attr"` - Docs []Doc `xml:"doc"` - Rules []Rule `xml:"rule"` - Fields []Field `xml:"field"` - Chassis []Chassis `xml:"chassis"` -} - -type Class struct { - Name string `xml:"name,attr"` - Handler string `xml:"handler,attr"` - Index string `xml:"index,attr"` - Label string `xml:"label,attr"` - Docs []Doc `xml:"doc"` - Methods []Method `xml:"method"` - Chassis []Chassis `xml:"chassis"` -} - -type Domain struct { - Name string `xml:"name,attr"` - Type string `xml:"type,attr"` - Label string `xml:"label,attr"` - Rules []Rule `xml:"rule"` - Docs []Doc `xml:"doc"` -} - -type Constant struct { - Name string `xml:"name,attr"` - Value int `xml:"value,attr"` - Class string `xml:"class,attr"` - Doc string `xml:"doc"` -} - -type Amqp struct { - Major int `xml:"major,attr"` - Minor int `xml:"minor,attr"` - Port int `xml:"port,attr"` - Comment string `xml:"comment,attr"` - - Constants []Constant `xml:"constant"` - Domains []Domain `xml:"domain"` - Classes []Class `xml:"class"` -} - -type renderer struct { - Root Amqp - bitcounter int -} - -type fieldset struct { - AmqpType string - NativeType string - Fields []Field - *renderer -} - -var ( - helpers = template.FuncMap{ - "public": public, - "private": private, - "clean": clean, - } - - packageTemplate = template.Must(template.New("package").Funcs(helpers).Parse(` - // Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. - // Use of this source code is governed by a BSD-style - // license that can be found in the LICENSE file. - // Source code and contact info at http://github.com/streadway/amqp - - /* GENERATED FILE - DO NOT EDIT */ - /* Rebuild from the spec/gen.go tool */ - - {{with .Root}} - package amqp - - import ( - "fmt" - "encoding/binary" - "io" - ) - - // Error codes that can be sent from the server during a connection or - // channel exception or used by the client to indicate a class of error like - // ErrCredentials. The text of the error is likely more interesting than - // these constants. - const ( - {{range $c := .Constants}} - {{if $c.IsError}}{{.Name | public}}{{else}}{{.Name | private}}{{end}} = {{.Value}}{{end}} - ) - - func isSoftExceptionCode(code int) bool { - switch code { - {{range $c := .Constants}} {{if $c.IsSoftError}} case {{$c.Value}}: - return true - {{end}}{{end}} - } - return false - } - - {{range .Classes}} - {{$class := .}} - {{range .Methods}} - {{$method := .}} - {{$struct := $.StructName $class.Name $method.Name}} - {{if .Docs}}/* {{range .Docs}} {{.Body | clean}} {{end}} */{{end}} - type {{$struct}} struct { - {{range .Fields}} - {{$.FieldName .}} {{$.FieldType . | $.NativeType}} {{if .Label}}// {{.Label}}{{end}}{{end}} - {{if .Content}}Properties properties - Body []byte{{end}} - } - - func (me *{{$struct}}) id() (uint16, uint16) { - return {{$class.Index}}, {{$method.Index}} - } - - func (me *{{$struct}}) wait() (bool) { - return {{.Synchronous}}{{if $.HasField "NoWait" .}} && !me.NoWait{{end}} - } - - {{if .Content}} - func (me *{{$struct}}) getContent() (properties, []byte) { - return me.Properties, me.Body - } - - func (me *{{$struct}}) setContent(props properties, body []byte) { - me.Properties, me.Body = props, body - } - {{end}} - func (me *{{$struct}}) write(w io.Writer) (err error) { - {{if $.HasType "bit" $method}}var bits byte{{end}} - {{.Fields | $.Fieldsets | $.Partial "enc-"}} - return - } - - func (me *{{$struct}}) read(r io.Reader) (err error) { - {{if $.HasType "bit" $method}}var bits byte{{end}} - {{.Fields | $.Fieldsets | $.Partial "dec-"}} - return - } - {{end}} - {{end}} - - func (me *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err error) { - mf := &methodFrame { - ChannelId: channel, - } - - if err = binary.Read(me.r, binary.BigEndian, &mf.ClassId); err != nil { - return - } - - if err = binary.Read(me.r, binary.BigEndian, &mf.MethodId); err != nil { - return - } - - switch mf.ClassId { - {{range .Classes}} - {{$class := .}} - case {{.Index}}: // {{.Name}} - switch mf.MethodId { - {{range .Methods}} - case {{.Index}}: // {{$class.Name}} {{.Name}} - //fmt.Println("NextMethod: class:{{$class.Index}} method:{{.Index}}") - method := &{{$.StructName $class.Name .Name}}{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - {{end}} - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - {{end}} - default: - return nil, fmt.Errorf("Bad method frame, unknown class %d", mf.ClassId) - } - - return mf, nil - } - {{end}} - - {{define "enc-bit"}} - {{range $off, $field := .Fields}} - if me.{{$field | $.FieldName}} { bits |= 1 << {{$off}} } - {{end}} - if err = binary.Write(w, binary.BigEndian, bits); err != nil { return } - {{end}} - {{define "enc-octet"}} - {{range .Fields}} if err = binary.Write(w, binary.BigEndian, me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - {{define "enc-shortshort"}} - {{range .Fields}} if err = binary.Write(w, binary.BigEndian, me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - {{define "enc-short"}} - {{range .Fields}} if err = binary.Write(w, binary.BigEndian, me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - {{define "enc-long"}} - {{range .Fields}} if err = binary.Write(w, binary.BigEndian, me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - {{define "enc-longlong"}} - {{range .Fields}} if err = binary.Write(w, binary.BigEndian, me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - {{define "enc-timestamp"}} - {{range .Fields}} if err = writeTimestamp(w, me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - {{define "enc-shortstr"}} - {{range .Fields}} if err = writeShortstr(w, me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - {{define "enc-longstr"}} - {{range .Fields}} if err = writeLongstr(w, me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - {{define "enc-table"}} - {{range .Fields}} if err = writeTable(w, me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - - {{define "dec-bit"}} - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - {{range $off, $field := .Fields}} me.{{$field | $.FieldName}} = (bits & (1 << {{$off}}) > 0) - {{end}} - {{end}} - {{define "dec-octet"}} - {{range .Fields}} if err = binary.Read(r, binary.BigEndian, &me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - {{define "dec-shortshort"}} - {{range .Fields}} if err = binary.Read(r, binary.BigEndian, &me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - {{define "dec-short"}} - {{range .Fields}} if err = binary.Read(r, binary.BigEndian, &me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - {{define "dec-long"}} - {{range .Fields}} if err = binary.Read(r, binary.BigEndian, &me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - {{define "dec-longlong"}} - {{range .Fields}} if err = binary.Read(r, binary.BigEndian, &me.{{. | $.FieldName}}); err != nil { return } - {{end}} - {{end}} - {{define "dec-timestamp"}} - {{range .Fields}} if me.{{. | $.FieldName}}, err = readTimestamp(r); err != nil { return } - {{end}} - {{end}} - {{define "dec-shortstr"}} - {{range .Fields}} if me.{{. | $.FieldName}}, err = readShortstr(r); err != nil { return } - {{end}} - {{end}} - {{define "dec-longstr"}} - {{range .Fields}} if me.{{. | $.FieldName}}, err = readLongstr(r); err != nil { return } - {{end}} - {{end}} - {{define "dec-table"}} - {{range .Fields}} if me.{{. | $.FieldName}}, err = readTable(r); err != nil { return } - {{end}} - {{end}} - - `)) -) - -func (me *Constant) IsError() bool { - return strings.Contains(me.Class, "error") -} - -func (me *Constant) IsSoftError() bool { - return me.Class == "soft-error" -} - -func (me *renderer) Partial(prefix string, fields []fieldset) (s string, err error) { - var buf bytes.Buffer - for _, set := range fields { - name := prefix + set.AmqpType - t := packageTemplate.Lookup(name) - if t == nil { - return "", errors.New(fmt.Sprintf("Missing template: %s", name)) - } - if err = t.Execute(&buf, set); err != nil { - return - } - } - return string(buf.Bytes()), nil -} - -// Groups the fields so that the right encoder/decoder can be called -func (me *renderer) Fieldsets(fields []Field) (f []fieldset, err error) { - if len(fields) > 0 { - for _, field := range fields { - cur := fieldset{} - cur.AmqpType, err = me.FieldType(field) - if err != nil { - return - } - - cur.NativeType, err = me.NativeType(cur.AmqpType) - if err != nil { - return - } - cur.Fields = append(cur.Fields, field) - f = append(f, cur) - } - - i, j := 0, 1 - for j < len(f) { - if f[i].AmqpType == f[j].AmqpType { - f[i].Fields = append(f[i].Fields, f[j].Fields...) - } else { - i++ - f[i] = f[j] - } - j++ - } - return f[:i+1], nil - } - - return -} - -func (me *renderer) HasType(typ string, method Method) bool { - for _, f := range method.Fields { - name, _ := me.FieldType(f) - if name == typ { - return true - } - } - return false -} - -func (me *renderer) HasField(field string, method Method) bool { - for _, f := range method.Fields { - name := me.FieldName(f) - if name == field { - return true - } - } - return false -} - -func (me *renderer) Domain(field Field) (domain Domain, err error) { - for _, domain = range me.Root.Domains { - if field.Domain == domain.Name { - return - } - } - return domain, nil - //return domain, ErrUnknownDomain -} - -func (me *renderer) FieldName(field Field) (t string) { - t = public(field.Name) - - if field.Reserved { - t = strings.ToLower(t) - } - - return -} - -func (me *renderer) FieldType(field Field) (t string, err error) { - t = field.Type - - if t == "" { - var domain Domain - domain, err = me.Domain(field) - if err != nil { - return "", err - } - t = domain.Type - } - - return -} - -func (me *renderer) NativeType(amqpType string) (t string, err error) { - if t, ok := amqpTypeToNative[amqpType]; ok { - return t, nil - } - return "", ErrUnknownType -} - -func (me *renderer) Tag(d Domain) string { - label := "`" - - label += `domain:"` + d.Name + `"` - - if len(d.Type) > 0 { - label += `,type:"` + d.Type + `"` - } - - label += "`" - - return label -} - -func (me *renderer) StructName(parts ...string) string { - return parts[0] + public(parts[1:]...) -} - -func clean(body string) (res string) { - return strings.Replace(body, "\r", "", -1) -} - -func private(parts ...string) string { - return export(regexp.MustCompile(`[-_]\w`), parts...) -} - -func public(parts ...string) string { - return export(regexp.MustCompile(`^\w|[-_]\w`), parts...) -} - -func export(delim *regexp.Regexp, parts ...string) (res string) { - for _, in := range parts { - - res += delim.ReplaceAllStringFunc(in, func(match string) string { - switch len(match) { - case 1: - return strings.ToUpper(match) - case 2: - return strings.ToUpper(match[1:]) - } - panic("unreachable") - }) - } - - return -} - -func main() { - var r renderer - - spec, err := ioutil.ReadAll(os.Stdin) - if err != nil { - log.Fatalln("Please pass spec on stdin", err) - } - - err = xml.Unmarshal(spec, &r.Root) - - if err != nil { - log.Fatalln("Could not parse XML:", err) - } - - if err = packageTemplate.Execute(os.Stdout, &r); err != nil { - log.Fatalln("Generate error: ", err) - } -} diff --git a/vendor/github.com/streadway/amqp/spec091.go b/vendor/github.com/streadway/amqp/spec091.go deleted file mode 100644 index a9538030392..00000000000 --- a/vendor/github.com/streadway/amqp/spec091.go +++ /dev/null @@ -1,3306 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -/* GENERATED FILE - DO NOT EDIT */ -/* Rebuild from the spec/gen.go tool */ - -package amqp - -import ( - "encoding/binary" - "fmt" - "io" -) - -// Error codes that can be sent from the server during a connection or -// channel exception or used by the client to indicate a class of error like -// ErrCredentials. The text of the error is likely more interesting than -// these constants. -const ( - frameMethod = 1 - frameHeader = 2 - frameBody = 3 - frameHeartbeat = 8 - frameMinSize = 4096 - frameEnd = 206 - replySuccess = 200 - ContentTooLarge = 311 - NoRoute = 312 - NoConsumers = 313 - ConnectionForced = 320 - InvalidPath = 402 - AccessRefused = 403 - NotFound = 404 - ResourceLocked = 405 - PreconditionFailed = 406 - FrameError = 501 - SyntaxError = 502 - CommandInvalid = 503 - ChannelError = 504 - UnexpectedFrame = 505 - ResourceError = 506 - NotAllowed = 530 - NotImplemented = 540 - InternalError = 541 -) - -func isSoftExceptionCode(code int) bool { - switch code { - case 311: - return true - case 312: - return true - case 313: - return true - case 403: - return true - case 404: - return true - case 405: - return true - case 406: - return true - - } - return false -} - -type connectionStart struct { - VersionMajor byte - VersionMinor byte - ServerProperties Table - Mechanisms string - Locales string -} - -func (me *connectionStart) id() (uint16, uint16) { - return 10, 10 -} - -func (me *connectionStart) wait() bool { - return true -} - -func (me *connectionStart) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, me.VersionMajor); err != nil { - return - } - if err = binary.Write(w, binary.BigEndian, me.VersionMinor); err != nil { - return - } - - if err = writeTable(w, me.ServerProperties); err != nil { - return - } - - if err = writeLongstr(w, me.Mechanisms); err != nil { - return - } - if err = writeLongstr(w, me.Locales); err != nil { - return - } - - return -} - -func (me *connectionStart) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &me.VersionMajor); err != nil { - return - } - if err = binary.Read(r, binary.BigEndian, &me.VersionMinor); err != nil { - return - } - - if me.ServerProperties, err = readTable(r); err != nil { - return - } - - if me.Mechanisms, err = readLongstr(r); err != nil { - return - } - if me.Locales, err = readLongstr(r); err != nil { - return - } - - return -} - -type connectionStartOk struct { - ClientProperties Table - Mechanism string - Response string - Locale string -} - -func (me *connectionStartOk) id() (uint16, uint16) { - return 10, 11 -} - -func (me *connectionStartOk) wait() bool { - return true -} - -func (me *connectionStartOk) write(w io.Writer) (err error) { - - if err = writeTable(w, me.ClientProperties); err != nil { - return - } - - if err = writeShortstr(w, me.Mechanism); err != nil { - return - } - - if err = writeLongstr(w, me.Response); err != nil { - return - } - - if err = writeShortstr(w, me.Locale); err != nil { - return - } - - return -} - -func (me *connectionStartOk) read(r io.Reader) (err error) { - - if me.ClientProperties, err = readTable(r); err != nil { - return - } - - if me.Mechanism, err = readShortstr(r); err != nil { - return - } - - if me.Response, err = readLongstr(r); err != nil { - return - } - - if me.Locale, err = readShortstr(r); err != nil { - return - } - - return -} - -type connectionSecure struct { - Challenge string -} - -func (me *connectionSecure) id() (uint16, uint16) { - return 10, 20 -} - -func (me *connectionSecure) wait() bool { - return true -} - -func (me *connectionSecure) write(w io.Writer) (err error) { - - if err = writeLongstr(w, me.Challenge); err != nil { - return - } - - return -} - -func (me *connectionSecure) read(r io.Reader) (err error) { - - if me.Challenge, err = readLongstr(r); err != nil { - return - } - - return -} - -type connectionSecureOk struct { - Response string -} - -func (me *connectionSecureOk) id() (uint16, uint16) { - return 10, 21 -} - -func (me *connectionSecureOk) wait() bool { - return true -} - -func (me *connectionSecureOk) write(w io.Writer) (err error) { - - if err = writeLongstr(w, me.Response); err != nil { - return - } - - return -} - -func (me *connectionSecureOk) read(r io.Reader) (err error) { - - if me.Response, err = readLongstr(r); err != nil { - return - } - - return -} - -type connectionTune struct { - ChannelMax uint16 - FrameMax uint32 - Heartbeat uint16 -} - -func (me *connectionTune) id() (uint16, uint16) { - return 10, 30 -} - -func (me *connectionTune) wait() bool { - return true -} - -func (me *connectionTune) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, me.ChannelMax); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, me.FrameMax); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, me.Heartbeat); err != nil { - return - } - - return -} - -func (me *connectionTune) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &me.ChannelMax); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &me.FrameMax); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &me.Heartbeat); err != nil { - return - } - - return -} - -type connectionTuneOk struct { - ChannelMax uint16 - FrameMax uint32 - Heartbeat uint16 -} - -func (me *connectionTuneOk) id() (uint16, uint16) { - return 10, 31 -} - -func (me *connectionTuneOk) wait() bool { - return true -} - -func (me *connectionTuneOk) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, me.ChannelMax); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, me.FrameMax); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, me.Heartbeat); err != nil { - return - } - - return -} - -func (me *connectionTuneOk) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &me.ChannelMax); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &me.FrameMax); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &me.Heartbeat); err != nil { - return - } - - return -} - -type connectionOpen struct { - VirtualHost string - reserved1 string - reserved2 bool -} - -func (me *connectionOpen) id() (uint16, uint16) { - return 10, 40 -} - -func (me *connectionOpen) wait() bool { - return true -} - -func (me *connectionOpen) write(w io.Writer) (err error) { - var bits byte - - if err = writeShortstr(w, me.VirtualHost); err != nil { - return - } - if err = writeShortstr(w, me.reserved1); err != nil { - return - } - - if me.reserved2 { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *connectionOpen) read(r io.Reader) (err error) { - var bits byte - - if me.VirtualHost, err = readShortstr(r); err != nil { - return - } - if me.reserved1, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.reserved2 = (bits&(1<<0) > 0) - - return -} - -type connectionOpenOk struct { - reserved1 string -} - -func (me *connectionOpenOk) id() (uint16, uint16) { - return 10, 41 -} - -func (me *connectionOpenOk) wait() bool { - return true -} - -func (me *connectionOpenOk) write(w io.Writer) (err error) { - - if err = writeShortstr(w, me.reserved1); err != nil { - return - } - - return -} - -func (me *connectionOpenOk) read(r io.Reader) (err error) { - - if me.reserved1, err = readShortstr(r); err != nil { - return - } - - return -} - -type connectionClose struct { - ReplyCode uint16 - ReplyText string - ClassId uint16 - MethodId uint16 -} - -func (me *connectionClose) id() (uint16, uint16) { - return 10, 50 -} - -func (me *connectionClose) wait() bool { - return true -} - -func (me *connectionClose) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, me.ReplyCode); err != nil { - return - } - - if err = writeShortstr(w, me.ReplyText); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, me.ClassId); err != nil { - return - } - if err = binary.Write(w, binary.BigEndian, me.MethodId); err != nil { - return - } - - return -} - -func (me *connectionClose) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &me.ReplyCode); err != nil { - return - } - - if me.ReplyText, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &me.ClassId); err != nil { - return - } - if err = binary.Read(r, binary.BigEndian, &me.MethodId); err != nil { - return - } - - return -} - -type connectionCloseOk struct { -} - -func (me *connectionCloseOk) id() (uint16, uint16) { - return 10, 51 -} - -func (me *connectionCloseOk) wait() bool { - return true -} - -func (me *connectionCloseOk) write(w io.Writer) (err error) { - - return -} - -func (me *connectionCloseOk) read(r io.Reader) (err error) { - - return -} - -type connectionBlocked struct { - Reason string -} - -func (me *connectionBlocked) id() (uint16, uint16) { - return 10, 60 -} - -func (me *connectionBlocked) wait() bool { - return false -} - -func (me *connectionBlocked) write(w io.Writer) (err error) { - - if err = writeShortstr(w, me.Reason); err != nil { - return - } - - return -} - -func (me *connectionBlocked) read(r io.Reader) (err error) { - - if me.Reason, err = readShortstr(r); err != nil { - return - } - - return -} - -type connectionUnblocked struct { -} - -func (me *connectionUnblocked) id() (uint16, uint16) { - return 10, 61 -} - -func (me *connectionUnblocked) wait() bool { - return false -} - -func (me *connectionUnblocked) write(w io.Writer) (err error) { - - return -} - -func (me *connectionUnblocked) read(r io.Reader) (err error) { - - return -} - -type channelOpen struct { - reserved1 string -} - -func (me *channelOpen) id() (uint16, uint16) { - return 20, 10 -} - -func (me *channelOpen) wait() bool { - return true -} - -func (me *channelOpen) write(w io.Writer) (err error) { - - if err = writeShortstr(w, me.reserved1); err != nil { - return - } - - return -} - -func (me *channelOpen) read(r io.Reader) (err error) { - - if me.reserved1, err = readShortstr(r); err != nil { - return - } - - return -} - -type channelOpenOk struct { - reserved1 string -} - -func (me *channelOpenOk) id() (uint16, uint16) { - return 20, 11 -} - -func (me *channelOpenOk) wait() bool { - return true -} - -func (me *channelOpenOk) write(w io.Writer) (err error) { - - if err = writeLongstr(w, me.reserved1); err != nil { - return - } - - return -} - -func (me *channelOpenOk) read(r io.Reader) (err error) { - - if me.reserved1, err = readLongstr(r); err != nil { - return - } - - return -} - -type channelFlow struct { - Active bool -} - -func (me *channelFlow) id() (uint16, uint16) { - return 20, 20 -} - -func (me *channelFlow) wait() bool { - return true -} - -func (me *channelFlow) write(w io.Writer) (err error) { - var bits byte - - if me.Active { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *channelFlow) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Active = (bits&(1<<0) > 0) - - return -} - -type channelFlowOk struct { - Active bool -} - -func (me *channelFlowOk) id() (uint16, uint16) { - return 20, 21 -} - -func (me *channelFlowOk) wait() bool { - return false -} - -func (me *channelFlowOk) write(w io.Writer) (err error) { - var bits byte - - if me.Active { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *channelFlowOk) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Active = (bits&(1<<0) > 0) - - return -} - -type channelClose struct { - ReplyCode uint16 - ReplyText string - ClassId uint16 - MethodId uint16 -} - -func (me *channelClose) id() (uint16, uint16) { - return 20, 40 -} - -func (me *channelClose) wait() bool { - return true -} - -func (me *channelClose) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, me.ReplyCode); err != nil { - return - } - - if err = writeShortstr(w, me.ReplyText); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, me.ClassId); err != nil { - return - } - if err = binary.Write(w, binary.BigEndian, me.MethodId); err != nil { - return - } - - return -} - -func (me *channelClose) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &me.ReplyCode); err != nil { - return - } - - if me.ReplyText, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &me.ClassId); err != nil { - return - } - if err = binary.Read(r, binary.BigEndian, &me.MethodId); err != nil { - return - } - - return -} - -type channelCloseOk struct { -} - -func (me *channelCloseOk) id() (uint16, uint16) { - return 20, 41 -} - -func (me *channelCloseOk) wait() bool { - return true -} - -func (me *channelCloseOk) write(w io.Writer) (err error) { - - return -} - -func (me *channelCloseOk) read(r io.Reader) (err error) { - - return -} - -type exchangeDeclare struct { - reserved1 uint16 - Exchange string - Type string - Passive bool - Durable bool - AutoDelete bool - Internal bool - NoWait bool - Arguments Table -} - -func (me *exchangeDeclare) id() (uint16, uint16) { - return 40, 10 -} - -func (me *exchangeDeclare) wait() bool { - return true && !me.NoWait -} - -func (me *exchangeDeclare) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.reserved1); err != nil { - return - } - - if err = writeShortstr(w, me.Exchange); err != nil { - return - } - if err = writeShortstr(w, me.Type); err != nil { - return - } - - if me.Passive { - bits |= 1 << 0 - } - - if me.Durable { - bits |= 1 << 1 - } - - if me.AutoDelete { - bits |= 1 << 2 - } - - if me.Internal { - bits |= 1 << 3 - } - - if me.NoWait { - bits |= 1 << 4 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeTable(w, me.Arguments); err != nil { - return - } - - return -} - -func (me *exchangeDeclare) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.reserved1); err != nil { - return - } - - if me.Exchange, err = readShortstr(r); err != nil { - return - } - if me.Type, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Passive = (bits&(1<<0) > 0) - me.Durable = (bits&(1<<1) > 0) - me.AutoDelete = (bits&(1<<2) > 0) - me.Internal = (bits&(1<<3) > 0) - me.NoWait = (bits&(1<<4) > 0) - - if me.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type exchangeDeclareOk struct { -} - -func (me *exchangeDeclareOk) id() (uint16, uint16) { - return 40, 11 -} - -func (me *exchangeDeclareOk) wait() bool { - return true -} - -func (me *exchangeDeclareOk) write(w io.Writer) (err error) { - - return -} - -func (me *exchangeDeclareOk) read(r io.Reader) (err error) { - - return -} - -type exchangeDelete struct { - reserved1 uint16 - Exchange string - IfUnused bool - NoWait bool -} - -func (me *exchangeDelete) id() (uint16, uint16) { - return 40, 20 -} - -func (me *exchangeDelete) wait() bool { - return true && !me.NoWait -} - -func (me *exchangeDelete) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.reserved1); err != nil { - return - } - - if err = writeShortstr(w, me.Exchange); err != nil { - return - } - - if me.IfUnused { - bits |= 1 << 0 - } - - if me.NoWait { - bits |= 1 << 1 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *exchangeDelete) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.reserved1); err != nil { - return - } - - if me.Exchange, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.IfUnused = (bits&(1<<0) > 0) - me.NoWait = (bits&(1<<1) > 0) - - return -} - -type exchangeDeleteOk struct { -} - -func (me *exchangeDeleteOk) id() (uint16, uint16) { - return 40, 21 -} - -func (me *exchangeDeleteOk) wait() bool { - return true -} - -func (me *exchangeDeleteOk) write(w io.Writer) (err error) { - - return -} - -func (me *exchangeDeleteOk) read(r io.Reader) (err error) { - - return -} - -type exchangeBind struct { - reserved1 uint16 - Destination string - Source string - RoutingKey string - NoWait bool - Arguments Table -} - -func (me *exchangeBind) id() (uint16, uint16) { - return 40, 30 -} - -func (me *exchangeBind) wait() bool { - return true && !me.NoWait -} - -func (me *exchangeBind) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.reserved1); err != nil { - return - } - - if err = writeShortstr(w, me.Destination); err != nil { - return - } - if err = writeShortstr(w, me.Source); err != nil { - return - } - if err = writeShortstr(w, me.RoutingKey); err != nil { - return - } - - if me.NoWait { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeTable(w, me.Arguments); err != nil { - return - } - - return -} - -func (me *exchangeBind) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.reserved1); err != nil { - return - } - - if me.Destination, err = readShortstr(r); err != nil { - return - } - if me.Source, err = readShortstr(r); err != nil { - return - } - if me.RoutingKey, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.NoWait = (bits&(1<<0) > 0) - - if me.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type exchangeBindOk struct { -} - -func (me *exchangeBindOk) id() (uint16, uint16) { - return 40, 31 -} - -func (me *exchangeBindOk) wait() bool { - return true -} - -func (me *exchangeBindOk) write(w io.Writer) (err error) { - - return -} - -func (me *exchangeBindOk) read(r io.Reader) (err error) { - - return -} - -type exchangeUnbind struct { - reserved1 uint16 - Destination string - Source string - RoutingKey string - NoWait bool - Arguments Table -} - -func (me *exchangeUnbind) id() (uint16, uint16) { - return 40, 40 -} - -func (me *exchangeUnbind) wait() bool { - return true && !me.NoWait -} - -func (me *exchangeUnbind) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.reserved1); err != nil { - return - } - - if err = writeShortstr(w, me.Destination); err != nil { - return - } - if err = writeShortstr(w, me.Source); err != nil { - return - } - if err = writeShortstr(w, me.RoutingKey); err != nil { - return - } - - if me.NoWait { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeTable(w, me.Arguments); err != nil { - return - } - - return -} - -func (me *exchangeUnbind) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.reserved1); err != nil { - return - } - - if me.Destination, err = readShortstr(r); err != nil { - return - } - if me.Source, err = readShortstr(r); err != nil { - return - } - if me.RoutingKey, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.NoWait = (bits&(1<<0) > 0) - - if me.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type exchangeUnbindOk struct { -} - -func (me *exchangeUnbindOk) id() (uint16, uint16) { - return 40, 51 -} - -func (me *exchangeUnbindOk) wait() bool { - return true -} - -func (me *exchangeUnbindOk) write(w io.Writer) (err error) { - - return -} - -func (me *exchangeUnbindOk) read(r io.Reader) (err error) { - - return -} - -type queueDeclare struct { - reserved1 uint16 - Queue string - Passive bool - Durable bool - Exclusive bool - AutoDelete bool - NoWait bool - Arguments Table -} - -func (me *queueDeclare) id() (uint16, uint16) { - return 50, 10 -} - -func (me *queueDeclare) wait() bool { - return true && !me.NoWait -} - -func (me *queueDeclare) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.reserved1); err != nil { - return - } - - if err = writeShortstr(w, me.Queue); err != nil { - return - } - - if me.Passive { - bits |= 1 << 0 - } - - if me.Durable { - bits |= 1 << 1 - } - - if me.Exclusive { - bits |= 1 << 2 - } - - if me.AutoDelete { - bits |= 1 << 3 - } - - if me.NoWait { - bits |= 1 << 4 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeTable(w, me.Arguments); err != nil { - return - } - - return -} - -func (me *queueDeclare) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.reserved1); err != nil { - return - } - - if me.Queue, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Passive = (bits&(1<<0) > 0) - me.Durable = (bits&(1<<1) > 0) - me.Exclusive = (bits&(1<<2) > 0) - me.AutoDelete = (bits&(1<<3) > 0) - me.NoWait = (bits&(1<<4) > 0) - - if me.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type queueDeclareOk struct { - Queue string - MessageCount uint32 - ConsumerCount uint32 -} - -func (me *queueDeclareOk) id() (uint16, uint16) { - return 50, 11 -} - -func (me *queueDeclareOk) wait() bool { - return true -} - -func (me *queueDeclareOk) write(w io.Writer) (err error) { - - if err = writeShortstr(w, me.Queue); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, me.MessageCount); err != nil { - return - } - if err = binary.Write(w, binary.BigEndian, me.ConsumerCount); err != nil { - return - } - - return -} - -func (me *queueDeclareOk) read(r io.Reader) (err error) { - - if me.Queue, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &me.MessageCount); err != nil { - return - } - if err = binary.Read(r, binary.BigEndian, &me.ConsumerCount); err != nil { - return - } - - return -} - -type queueBind struct { - reserved1 uint16 - Queue string - Exchange string - RoutingKey string - NoWait bool - Arguments Table -} - -func (me *queueBind) id() (uint16, uint16) { - return 50, 20 -} - -func (me *queueBind) wait() bool { - return true && !me.NoWait -} - -func (me *queueBind) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.reserved1); err != nil { - return - } - - if err = writeShortstr(w, me.Queue); err != nil { - return - } - if err = writeShortstr(w, me.Exchange); err != nil { - return - } - if err = writeShortstr(w, me.RoutingKey); err != nil { - return - } - - if me.NoWait { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeTable(w, me.Arguments); err != nil { - return - } - - return -} - -func (me *queueBind) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.reserved1); err != nil { - return - } - - if me.Queue, err = readShortstr(r); err != nil { - return - } - if me.Exchange, err = readShortstr(r); err != nil { - return - } - if me.RoutingKey, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.NoWait = (bits&(1<<0) > 0) - - if me.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type queueBindOk struct { -} - -func (me *queueBindOk) id() (uint16, uint16) { - return 50, 21 -} - -func (me *queueBindOk) wait() bool { - return true -} - -func (me *queueBindOk) write(w io.Writer) (err error) { - - return -} - -func (me *queueBindOk) read(r io.Reader) (err error) { - - return -} - -type queueUnbind struct { - reserved1 uint16 - Queue string - Exchange string - RoutingKey string - Arguments Table -} - -func (me *queueUnbind) id() (uint16, uint16) { - return 50, 50 -} - -func (me *queueUnbind) wait() bool { - return true -} - -func (me *queueUnbind) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, me.reserved1); err != nil { - return - } - - if err = writeShortstr(w, me.Queue); err != nil { - return - } - if err = writeShortstr(w, me.Exchange); err != nil { - return - } - if err = writeShortstr(w, me.RoutingKey); err != nil { - return - } - - if err = writeTable(w, me.Arguments); err != nil { - return - } - - return -} - -func (me *queueUnbind) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &me.reserved1); err != nil { - return - } - - if me.Queue, err = readShortstr(r); err != nil { - return - } - if me.Exchange, err = readShortstr(r); err != nil { - return - } - if me.RoutingKey, err = readShortstr(r); err != nil { - return - } - - if me.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type queueUnbindOk struct { -} - -func (me *queueUnbindOk) id() (uint16, uint16) { - return 50, 51 -} - -func (me *queueUnbindOk) wait() bool { - return true -} - -func (me *queueUnbindOk) write(w io.Writer) (err error) { - - return -} - -func (me *queueUnbindOk) read(r io.Reader) (err error) { - - return -} - -type queuePurge struct { - reserved1 uint16 - Queue string - NoWait bool -} - -func (me *queuePurge) id() (uint16, uint16) { - return 50, 30 -} - -func (me *queuePurge) wait() bool { - return true && !me.NoWait -} - -func (me *queuePurge) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.reserved1); err != nil { - return - } - - if err = writeShortstr(w, me.Queue); err != nil { - return - } - - if me.NoWait { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *queuePurge) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.reserved1); err != nil { - return - } - - if me.Queue, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.NoWait = (bits&(1<<0) > 0) - - return -} - -type queuePurgeOk struct { - MessageCount uint32 -} - -func (me *queuePurgeOk) id() (uint16, uint16) { - return 50, 31 -} - -func (me *queuePurgeOk) wait() bool { - return true -} - -func (me *queuePurgeOk) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, me.MessageCount); err != nil { - return - } - - return -} - -func (me *queuePurgeOk) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &me.MessageCount); err != nil { - return - } - - return -} - -type queueDelete struct { - reserved1 uint16 - Queue string - IfUnused bool - IfEmpty bool - NoWait bool -} - -func (me *queueDelete) id() (uint16, uint16) { - return 50, 40 -} - -func (me *queueDelete) wait() bool { - return true && !me.NoWait -} - -func (me *queueDelete) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.reserved1); err != nil { - return - } - - if err = writeShortstr(w, me.Queue); err != nil { - return - } - - if me.IfUnused { - bits |= 1 << 0 - } - - if me.IfEmpty { - bits |= 1 << 1 - } - - if me.NoWait { - bits |= 1 << 2 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *queueDelete) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.reserved1); err != nil { - return - } - - if me.Queue, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.IfUnused = (bits&(1<<0) > 0) - me.IfEmpty = (bits&(1<<1) > 0) - me.NoWait = (bits&(1<<2) > 0) - - return -} - -type queueDeleteOk struct { - MessageCount uint32 -} - -func (me *queueDeleteOk) id() (uint16, uint16) { - return 50, 41 -} - -func (me *queueDeleteOk) wait() bool { - return true -} - -func (me *queueDeleteOk) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, me.MessageCount); err != nil { - return - } - - return -} - -func (me *queueDeleteOk) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &me.MessageCount); err != nil { - return - } - - return -} - -type basicQos struct { - PrefetchSize uint32 - PrefetchCount uint16 - Global bool -} - -func (me *basicQos) id() (uint16, uint16) { - return 60, 10 -} - -func (me *basicQos) wait() bool { - return true -} - -func (me *basicQos) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.PrefetchSize); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, me.PrefetchCount); err != nil { - return - } - - if me.Global { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *basicQos) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.PrefetchSize); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &me.PrefetchCount); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Global = (bits&(1<<0) > 0) - - return -} - -type basicQosOk struct { -} - -func (me *basicQosOk) id() (uint16, uint16) { - return 60, 11 -} - -func (me *basicQosOk) wait() bool { - return true -} - -func (me *basicQosOk) write(w io.Writer) (err error) { - - return -} - -func (me *basicQosOk) read(r io.Reader) (err error) { - - return -} - -type basicConsume struct { - reserved1 uint16 - Queue string - ConsumerTag string - NoLocal bool - NoAck bool - Exclusive bool - NoWait bool - Arguments Table -} - -func (me *basicConsume) id() (uint16, uint16) { - return 60, 20 -} - -func (me *basicConsume) wait() bool { - return true && !me.NoWait -} - -func (me *basicConsume) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.reserved1); err != nil { - return - } - - if err = writeShortstr(w, me.Queue); err != nil { - return - } - if err = writeShortstr(w, me.ConsumerTag); err != nil { - return - } - - if me.NoLocal { - bits |= 1 << 0 - } - - if me.NoAck { - bits |= 1 << 1 - } - - if me.Exclusive { - bits |= 1 << 2 - } - - if me.NoWait { - bits |= 1 << 3 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeTable(w, me.Arguments); err != nil { - return - } - - return -} - -func (me *basicConsume) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.reserved1); err != nil { - return - } - - if me.Queue, err = readShortstr(r); err != nil { - return - } - if me.ConsumerTag, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.NoLocal = (bits&(1<<0) > 0) - me.NoAck = (bits&(1<<1) > 0) - me.Exclusive = (bits&(1<<2) > 0) - me.NoWait = (bits&(1<<3) > 0) - - if me.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type basicConsumeOk struct { - ConsumerTag string -} - -func (me *basicConsumeOk) id() (uint16, uint16) { - return 60, 21 -} - -func (me *basicConsumeOk) wait() bool { - return true -} - -func (me *basicConsumeOk) write(w io.Writer) (err error) { - - if err = writeShortstr(w, me.ConsumerTag); err != nil { - return - } - - return -} - -func (me *basicConsumeOk) read(r io.Reader) (err error) { - - if me.ConsumerTag, err = readShortstr(r); err != nil { - return - } - - return -} - -type basicCancel struct { - ConsumerTag string - NoWait bool -} - -func (me *basicCancel) id() (uint16, uint16) { - return 60, 30 -} - -func (me *basicCancel) wait() bool { - return true && !me.NoWait -} - -func (me *basicCancel) write(w io.Writer) (err error) { - var bits byte - - if err = writeShortstr(w, me.ConsumerTag); err != nil { - return - } - - if me.NoWait { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *basicCancel) read(r io.Reader) (err error) { - var bits byte - - if me.ConsumerTag, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.NoWait = (bits&(1<<0) > 0) - - return -} - -type basicCancelOk struct { - ConsumerTag string -} - -func (me *basicCancelOk) id() (uint16, uint16) { - return 60, 31 -} - -func (me *basicCancelOk) wait() bool { - return true -} - -func (me *basicCancelOk) write(w io.Writer) (err error) { - - if err = writeShortstr(w, me.ConsumerTag); err != nil { - return - } - - return -} - -func (me *basicCancelOk) read(r io.Reader) (err error) { - - if me.ConsumerTag, err = readShortstr(r); err != nil { - return - } - - return -} - -type basicPublish struct { - reserved1 uint16 - Exchange string - RoutingKey string - Mandatory bool - Immediate bool - Properties properties - Body []byte -} - -func (me *basicPublish) id() (uint16, uint16) { - return 60, 40 -} - -func (me *basicPublish) wait() bool { - return false -} - -func (me *basicPublish) getContent() (properties, []byte) { - return me.Properties, me.Body -} - -func (me *basicPublish) setContent(props properties, body []byte) { - me.Properties, me.Body = props, body -} - -func (me *basicPublish) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.reserved1); err != nil { - return - } - - if err = writeShortstr(w, me.Exchange); err != nil { - return - } - if err = writeShortstr(w, me.RoutingKey); err != nil { - return - } - - if me.Mandatory { - bits |= 1 << 0 - } - - if me.Immediate { - bits |= 1 << 1 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *basicPublish) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.reserved1); err != nil { - return - } - - if me.Exchange, err = readShortstr(r); err != nil { - return - } - if me.RoutingKey, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Mandatory = (bits&(1<<0) > 0) - me.Immediate = (bits&(1<<1) > 0) - - return -} - -type basicReturn struct { - ReplyCode uint16 - ReplyText string - Exchange string - RoutingKey string - Properties properties - Body []byte -} - -func (me *basicReturn) id() (uint16, uint16) { - return 60, 50 -} - -func (me *basicReturn) wait() bool { - return false -} - -func (me *basicReturn) getContent() (properties, []byte) { - return me.Properties, me.Body -} - -func (me *basicReturn) setContent(props properties, body []byte) { - me.Properties, me.Body = props, body -} - -func (me *basicReturn) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, me.ReplyCode); err != nil { - return - } - - if err = writeShortstr(w, me.ReplyText); err != nil { - return - } - if err = writeShortstr(w, me.Exchange); err != nil { - return - } - if err = writeShortstr(w, me.RoutingKey); err != nil { - return - } - - return -} - -func (me *basicReturn) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &me.ReplyCode); err != nil { - return - } - - if me.ReplyText, err = readShortstr(r); err != nil { - return - } - if me.Exchange, err = readShortstr(r); err != nil { - return - } - if me.RoutingKey, err = readShortstr(r); err != nil { - return - } - - return -} - -type basicDeliver struct { - ConsumerTag string - DeliveryTag uint64 - Redelivered bool - Exchange string - RoutingKey string - Properties properties - Body []byte -} - -func (me *basicDeliver) id() (uint16, uint16) { - return 60, 60 -} - -func (me *basicDeliver) wait() bool { - return false -} - -func (me *basicDeliver) getContent() (properties, []byte) { - return me.Properties, me.Body -} - -func (me *basicDeliver) setContent(props properties, body []byte) { - me.Properties, me.Body = props, body -} - -func (me *basicDeliver) write(w io.Writer) (err error) { - var bits byte - - if err = writeShortstr(w, me.ConsumerTag); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, me.DeliveryTag); err != nil { - return - } - - if me.Redelivered { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeShortstr(w, me.Exchange); err != nil { - return - } - if err = writeShortstr(w, me.RoutingKey); err != nil { - return - } - - return -} - -func (me *basicDeliver) read(r io.Reader) (err error) { - var bits byte - - if me.ConsumerTag, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &me.DeliveryTag); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Redelivered = (bits&(1<<0) > 0) - - if me.Exchange, err = readShortstr(r); err != nil { - return - } - if me.RoutingKey, err = readShortstr(r); err != nil { - return - } - - return -} - -type basicGet struct { - reserved1 uint16 - Queue string - NoAck bool -} - -func (me *basicGet) id() (uint16, uint16) { - return 60, 70 -} - -func (me *basicGet) wait() bool { - return true -} - -func (me *basicGet) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.reserved1); err != nil { - return - } - - if err = writeShortstr(w, me.Queue); err != nil { - return - } - - if me.NoAck { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *basicGet) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.reserved1); err != nil { - return - } - - if me.Queue, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.NoAck = (bits&(1<<0) > 0) - - return -} - -type basicGetOk struct { - DeliveryTag uint64 - Redelivered bool - Exchange string - RoutingKey string - MessageCount uint32 - Properties properties - Body []byte -} - -func (me *basicGetOk) id() (uint16, uint16) { - return 60, 71 -} - -func (me *basicGetOk) wait() bool { - return true -} - -func (me *basicGetOk) getContent() (properties, []byte) { - return me.Properties, me.Body -} - -func (me *basicGetOk) setContent(props properties, body []byte) { - me.Properties, me.Body = props, body -} - -func (me *basicGetOk) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.DeliveryTag); err != nil { - return - } - - if me.Redelivered { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeShortstr(w, me.Exchange); err != nil { - return - } - if err = writeShortstr(w, me.RoutingKey); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, me.MessageCount); err != nil { - return - } - - return -} - -func (me *basicGetOk) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.DeliveryTag); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Redelivered = (bits&(1<<0) > 0) - - if me.Exchange, err = readShortstr(r); err != nil { - return - } - if me.RoutingKey, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &me.MessageCount); err != nil { - return - } - - return -} - -type basicGetEmpty struct { - reserved1 string -} - -func (me *basicGetEmpty) id() (uint16, uint16) { - return 60, 72 -} - -func (me *basicGetEmpty) wait() bool { - return true -} - -func (me *basicGetEmpty) write(w io.Writer) (err error) { - - if err = writeShortstr(w, me.reserved1); err != nil { - return - } - - return -} - -func (me *basicGetEmpty) read(r io.Reader) (err error) { - - if me.reserved1, err = readShortstr(r); err != nil { - return - } - - return -} - -type basicAck struct { - DeliveryTag uint64 - Multiple bool -} - -func (me *basicAck) id() (uint16, uint16) { - return 60, 80 -} - -func (me *basicAck) wait() bool { - return false -} - -func (me *basicAck) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.DeliveryTag); err != nil { - return - } - - if me.Multiple { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *basicAck) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.DeliveryTag); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Multiple = (bits&(1<<0) > 0) - - return -} - -type basicReject struct { - DeliveryTag uint64 - Requeue bool -} - -func (me *basicReject) id() (uint16, uint16) { - return 60, 90 -} - -func (me *basicReject) wait() bool { - return false -} - -func (me *basicReject) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.DeliveryTag); err != nil { - return - } - - if me.Requeue { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *basicReject) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.DeliveryTag); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Requeue = (bits&(1<<0) > 0) - - return -} - -type basicRecoverAsync struct { - Requeue bool -} - -func (me *basicRecoverAsync) id() (uint16, uint16) { - return 60, 100 -} - -func (me *basicRecoverAsync) wait() bool { - return false -} - -func (me *basicRecoverAsync) write(w io.Writer) (err error) { - var bits byte - - if me.Requeue { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *basicRecoverAsync) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Requeue = (bits&(1<<0) > 0) - - return -} - -type basicRecover struct { - Requeue bool -} - -func (me *basicRecover) id() (uint16, uint16) { - return 60, 110 -} - -func (me *basicRecover) wait() bool { - return true -} - -func (me *basicRecover) write(w io.Writer) (err error) { - var bits byte - - if me.Requeue { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *basicRecover) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Requeue = (bits&(1<<0) > 0) - - return -} - -type basicRecoverOk struct { -} - -func (me *basicRecoverOk) id() (uint16, uint16) { - return 60, 111 -} - -func (me *basicRecoverOk) wait() bool { - return true -} - -func (me *basicRecoverOk) write(w io.Writer) (err error) { - - return -} - -func (me *basicRecoverOk) read(r io.Reader) (err error) { - - return -} - -type basicNack struct { - DeliveryTag uint64 - Multiple bool - Requeue bool -} - -func (me *basicNack) id() (uint16, uint16) { - return 60, 120 -} - -func (me *basicNack) wait() bool { - return false -} - -func (me *basicNack) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, me.DeliveryTag); err != nil { - return - } - - if me.Multiple { - bits |= 1 << 0 - } - - if me.Requeue { - bits |= 1 << 1 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *basicNack) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &me.DeliveryTag); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Multiple = (bits&(1<<0) > 0) - me.Requeue = (bits&(1<<1) > 0) - - return -} - -type txSelect struct { -} - -func (me *txSelect) id() (uint16, uint16) { - return 90, 10 -} - -func (me *txSelect) wait() bool { - return true -} - -func (me *txSelect) write(w io.Writer) (err error) { - - return -} - -func (me *txSelect) read(r io.Reader) (err error) { - - return -} - -type txSelectOk struct { -} - -func (me *txSelectOk) id() (uint16, uint16) { - return 90, 11 -} - -func (me *txSelectOk) wait() bool { - return true -} - -func (me *txSelectOk) write(w io.Writer) (err error) { - - return -} - -func (me *txSelectOk) read(r io.Reader) (err error) { - - return -} - -type txCommit struct { -} - -func (me *txCommit) id() (uint16, uint16) { - return 90, 20 -} - -func (me *txCommit) wait() bool { - return true -} - -func (me *txCommit) write(w io.Writer) (err error) { - - return -} - -func (me *txCommit) read(r io.Reader) (err error) { - - return -} - -type txCommitOk struct { -} - -func (me *txCommitOk) id() (uint16, uint16) { - return 90, 21 -} - -func (me *txCommitOk) wait() bool { - return true -} - -func (me *txCommitOk) write(w io.Writer) (err error) { - - return -} - -func (me *txCommitOk) read(r io.Reader) (err error) { - - return -} - -type txRollback struct { -} - -func (me *txRollback) id() (uint16, uint16) { - return 90, 30 -} - -func (me *txRollback) wait() bool { - return true -} - -func (me *txRollback) write(w io.Writer) (err error) { - - return -} - -func (me *txRollback) read(r io.Reader) (err error) { - - return -} - -type txRollbackOk struct { -} - -func (me *txRollbackOk) id() (uint16, uint16) { - return 90, 31 -} - -func (me *txRollbackOk) wait() bool { - return true -} - -func (me *txRollbackOk) write(w io.Writer) (err error) { - - return -} - -func (me *txRollbackOk) read(r io.Reader) (err error) { - - return -} - -type confirmSelect struct { - Nowait bool -} - -func (me *confirmSelect) id() (uint16, uint16) { - return 85, 10 -} - -func (me *confirmSelect) wait() bool { - return true -} - -func (me *confirmSelect) write(w io.Writer) (err error) { - var bits byte - - if me.Nowait { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (me *confirmSelect) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - me.Nowait = (bits&(1<<0) > 0) - - return -} - -type confirmSelectOk struct { -} - -func (me *confirmSelectOk) id() (uint16, uint16) { - return 85, 11 -} - -func (me *confirmSelectOk) wait() bool { - return true -} - -func (me *confirmSelectOk) write(w io.Writer) (err error) { - - return -} - -func (me *confirmSelectOk) read(r io.Reader) (err error) { - - return -} - -func (me *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err error) { - mf := &methodFrame{ - ChannelId: channel, - } - - if err = binary.Read(me.r, binary.BigEndian, &mf.ClassId); err != nil { - return - } - - if err = binary.Read(me.r, binary.BigEndian, &mf.MethodId); err != nil { - return - } - - switch mf.ClassId { - - case 10: // connection - switch mf.MethodId { - - case 10: // connection start - //fmt.Println("NextMethod: class:10 method:10") - method := &connectionStart{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 11: // connection start-ok - //fmt.Println("NextMethod: class:10 method:11") - method := &connectionStartOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 20: // connection secure - //fmt.Println("NextMethod: class:10 method:20") - method := &connectionSecure{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 21: // connection secure-ok - //fmt.Println("NextMethod: class:10 method:21") - method := &connectionSecureOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 30: // connection tune - //fmt.Println("NextMethod: class:10 method:30") - method := &connectionTune{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 31: // connection tune-ok - //fmt.Println("NextMethod: class:10 method:31") - method := &connectionTuneOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 40: // connection open - //fmt.Println("NextMethod: class:10 method:40") - method := &connectionOpen{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 41: // connection open-ok - //fmt.Println("NextMethod: class:10 method:41") - method := &connectionOpenOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 50: // connection close - //fmt.Println("NextMethod: class:10 method:50") - method := &connectionClose{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 51: // connection close-ok - //fmt.Println("NextMethod: class:10 method:51") - method := &connectionCloseOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 60: // connection blocked - //fmt.Println("NextMethod: class:10 method:60") - method := &connectionBlocked{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 61: // connection unblocked - //fmt.Println("NextMethod: class:10 method:61") - method := &connectionUnblocked{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - case 20: // channel - switch mf.MethodId { - - case 10: // channel open - //fmt.Println("NextMethod: class:20 method:10") - method := &channelOpen{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 11: // channel open-ok - //fmt.Println("NextMethod: class:20 method:11") - method := &channelOpenOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 20: // channel flow - //fmt.Println("NextMethod: class:20 method:20") - method := &channelFlow{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 21: // channel flow-ok - //fmt.Println("NextMethod: class:20 method:21") - method := &channelFlowOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 40: // channel close - //fmt.Println("NextMethod: class:20 method:40") - method := &channelClose{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 41: // channel close-ok - //fmt.Println("NextMethod: class:20 method:41") - method := &channelCloseOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - case 40: // exchange - switch mf.MethodId { - - case 10: // exchange declare - //fmt.Println("NextMethod: class:40 method:10") - method := &exchangeDeclare{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 11: // exchange declare-ok - //fmt.Println("NextMethod: class:40 method:11") - method := &exchangeDeclareOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 20: // exchange delete - //fmt.Println("NextMethod: class:40 method:20") - method := &exchangeDelete{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 21: // exchange delete-ok - //fmt.Println("NextMethod: class:40 method:21") - method := &exchangeDeleteOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 30: // exchange bind - //fmt.Println("NextMethod: class:40 method:30") - method := &exchangeBind{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 31: // exchange bind-ok - //fmt.Println("NextMethod: class:40 method:31") - method := &exchangeBindOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 40: // exchange unbind - //fmt.Println("NextMethod: class:40 method:40") - method := &exchangeUnbind{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 51: // exchange unbind-ok - //fmt.Println("NextMethod: class:40 method:51") - method := &exchangeUnbindOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - case 50: // queue - switch mf.MethodId { - - case 10: // queue declare - //fmt.Println("NextMethod: class:50 method:10") - method := &queueDeclare{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 11: // queue declare-ok - //fmt.Println("NextMethod: class:50 method:11") - method := &queueDeclareOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 20: // queue bind - //fmt.Println("NextMethod: class:50 method:20") - method := &queueBind{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 21: // queue bind-ok - //fmt.Println("NextMethod: class:50 method:21") - method := &queueBindOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 50: // queue unbind - //fmt.Println("NextMethod: class:50 method:50") - method := &queueUnbind{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 51: // queue unbind-ok - //fmt.Println("NextMethod: class:50 method:51") - method := &queueUnbindOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 30: // queue purge - //fmt.Println("NextMethod: class:50 method:30") - method := &queuePurge{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 31: // queue purge-ok - //fmt.Println("NextMethod: class:50 method:31") - method := &queuePurgeOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 40: // queue delete - //fmt.Println("NextMethod: class:50 method:40") - method := &queueDelete{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 41: // queue delete-ok - //fmt.Println("NextMethod: class:50 method:41") - method := &queueDeleteOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - case 60: // basic - switch mf.MethodId { - - case 10: // basic qos - //fmt.Println("NextMethod: class:60 method:10") - method := &basicQos{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 11: // basic qos-ok - //fmt.Println("NextMethod: class:60 method:11") - method := &basicQosOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 20: // basic consume - //fmt.Println("NextMethod: class:60 method:20") - method := &basicConsume{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 21: // basic consume-ok - //fmt.Println("NextMethod: class:60 method:21") - method := &basicConsumeOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 30: // basic cancel - //fmt.Println("NextMethod: class:60 method:30") - method := &basicCancel{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 31: // basic cancel-ok - //fmt.Println("NextMethod: class:60 method:31") - method := &basicCancelOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 40: // basic publish - //fmt.Println("NextMethod: class:60 method:40") - method := &basicPublish{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 50: // basic return - //fmt.Println("NextMethod: class:60 method:50") - method := &basicReturn{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 60: // basic deliver - //fmt.Println("NextMethod: class:60 method:60") - method := &basicDeliver{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 70: // basic get - //fmt.Println("NextMethod: class:60 method:70") - method := &basicGet{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 71: // basic get-ok - //fmt.Println("NextMethod: class:60 method:71") - method := &basicGetOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 72: // basic get-empty - //fmt.Println("NextMethod: class:60 method:72") - method := &basicGetEmpty{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 80: // basic ack - //fmt.Println("NextMethod: class:60 method:80") - method := &basicAck{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 90: // basic reject - //fmt.Println("NextMethod: class:60 method:90") - method := &basicReject{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 100: // basic recover-async - //fmt.Println("NextMethod: class:60 method:100") - method := &basicRecoverAsync{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 110: // basic recover - //fmt.Println("NextMethod: class:60 method:110") - method := &basicRecover{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 111: // basic recover-ok - //fmt.Println("NextMethod: class:60 method:111") - method := &basicRecoverOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 120: // basic nack - //fmt.Println("NextMethod: class:60 method:120") - method := &basicNack{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - case 90: // tx - switch mf.MethodId { - - case 10: // tx select - //fmt.Println("NextMethod: class:90 method:10") - method := &txSelect{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 11: // tx select-ok - //fmt.Println("NextMethod: class:90 method:11") - method := &txSelectOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 20: // tx commit - //fmt.Println("NextMethod: class:90 method:20") - method := &txCommit{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 21: // tx commit-ok - //fmt.Println("NextMethod: class:90 method:21") - method := &txCommitOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 30: // tx rollback - //fmt.Println("NextMethod: class:90 method:30") - method := &txRollback{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 31: // tx rollback-ok - //fmt.Println("NextMethod: class:90 method:31") - method := &txRollbackOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - case 85: // confirm - switch mf.MethodId { - - case 10: // confirm select - //fmt.Println("NextMethod: class:85 method:10") - method := &confirmSelect{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - case 11: // confirm select-ok - //fmt.Println("NextMethod: class:85 method:11") - method := &confirmSelectOk{} - if err = method.read(me.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - default: - return nil, fmt.Errorf("Bad method frame, unknown class %d", mf.ClassId) - } - - return mf, nil -} diff --git a/vendor/github.com/streadway/amqp/tls_test.go b/vendor/github.com/streadway/amqp/tls_test.go deleted file mode 100644 index a0795b6413c..00000000000 --- a/vendor/github.com/streadway/amqp/tls_test.go +++ /dev/null @@ -1,218 +0,0 @@ -package amqp_test - -import ( - "crypto/tls" - "crypto/x509" - "fmt" - "github.com/streadway/amqp" - "io" - "net" - "testing" - "time" -) - -type tlsServer struct { - net.Listener - URL string - Config *tls.Config - Header chan []byte -} - -// Captures the header for each accepted connection -func (s *tlsServer) Serve() { - for { - c, err := s.Accept() - if err != nil { - return - } - - header := make([]byte, 4) - io.ReadFull(c, header) - s.Header <- header - c.Write([]byte{'A', 'M', 'Q', 'P', 0, 0, 0, 0}) - c.Close() - } -} - -func tlsConfig() *tls.Config { - cfg := new(tls.Config) - - cfg.ClientCAs = x509.NewCertPool() - cfg.ClientCAs.AppendCertsFromPEM([]byte(caCert)) - - cert, err := tls.X509KeyPair([]byte(serverCert), []byte(serverKey)) - if err != nil { - panic(err) - } - - cfg.Certificates = append(cfg.Certificates, cert) - cfg.ClientAuth = tls.RequireAndVerifyClientCert - - return cfg -} - -func startTlsServer() tlsServer { - cfg := tlsConfig() - - l, err := tls.Listen("tcp", "127.0.0.1:0", cfg) - if err != nil { - panic(err) - } - - s := tlsServer{ - Listener: l, - Config: cfg, - URL: fmt.Sprintf("amqps://%s/", l.Addr().String()), - Header: make(chan []byte, 1), - } - - go s.Serve() - return s -} - -// Tests that the server has handshaked the connection and seen the client -// protocol announcement. Does not nest that the connection.open is successful. -func TestTLSHandshake(t *testing.T) { - srv := startTlsServer() - defer srv.Close() - - cfg := new(tls.Config) - cfg.RootCAs = x509.NewCertPool() - cfg.RootCAs.AppendCertsFromPEM([]byte(caCert)) - - cert, _ := tls.X509KeyPair([]byte(clientCert), []byte(clientKey)) - cfg.Certificates = append(cfg.Certificates, cert) - - _, err := amqp.DialTLS(srv.URL, cfg) - - select { - case <-time.After(10 * time.Millisecond): - t.Fatalf("did not succeed to handshake the TLS connection after 10ms") - case header := <-srv.Header: - if string(header) != "AMQP" { - t.Fatalf("expected to handshake a TLS connection, got err: %v", err) - } - } -} - -const caCert = ` ------BEGIN CERTIFICATE----- -MIICxjCCAa6gAwIBAgIJANWuMWMQSxvdMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV -BAMTCE15VGVzdENBMB4XDTE0MDEyNzE5NTIyMloXDTI0MDEyNTE5NTIyMlowEzER -MA8GA1UEAxMITXlUZXN0Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQDBsIrkW4ob9Z/gzR2/Maa2stbutry6/vvz8eiJwIKIbaHGwqtFOUGiWeKw7H76 -IH3SjTAhNQY2hoKPyH41D36sDJkYBRyHFJTK/6ffvOhpyLnuXJAnoS62eKPSNUAx -5i/lkHj42ESutYAH9qbHCI/gBm9G4WmhGAyA16xzC1n07JObl6KFoY1PqHKl823z -mvF47I24DzemEfjdwC9nAAX/pGYOg9FA9nQv7NnhlsJMxueCx55RNU1ADRoqsbfE -T0CQTOT4ryugGrUp9J4Cwen6YbXZrS6+Kff5SQCAns0Qu8/bwj0DKkuBGLF+Mnwe -mq9bMzyZPUrPM3Gu48ao8YAfAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0P -BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCBwXGblRxIEOlEP6ANZ1C8AHWyG8lR -CQduFclc0tmyCCz5fnyLK0aGu9LhXXe6/HSKqgs4mJqeqYOojdjkfOme/YdwDzjK -WIf0kRYQHcB6NeyEZwW8C7subTP1Xw6zbAmjvQrtCGvRM+fi3/cs1sSSkd/EoRk4 -7GM9qQl/JIIoCOGncninf2NQm5YSpbit6/mOQD7EhqXsw+bX+IRh3DHC1Apv/PoA -HlDNeM4vjWaBxsmvRSndrIvew1czboFM18oRSSIqAkU7dKZ0SbC11grzmNxMG2aD -f9y8FIG6RK/SEaOZuc+uBGXx7tj7dczpE/2puqYcaVGwcv4kkrC/ZuRm ------END CERTIFICATE----- -` - -const serverCert = ` ------BEGIN CERTIFICATE----- -MIIC8zCCAdugAwIBAgIBATANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl -c3RDQTAeFw0xNDAxMjcxOTUyMjNaFw0yNDAxMjUxOTUyMjNaMCUxEjAQBgNVBAMT -CTEyNy4wLjAuMTEPMA0GA1UEChMGc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAxYAKbeGyg0gP0xwVsZsufzk/SUCtD44Gp3lQYQ9QumQ1IVZu -PmZWwPWrzI93a1Abruz6ZhXaB3jcL5QPAy1N44IiFgVN45CZXBsqkpJe/abzRFOV -DRnHxattPDHdgwML5d3nURKGUM/7+ACj5E4pZEDlM3RIjIKVd+doJsL7n6myO8FE -tIpt4vTz1MFp3F+ntPnHU3BZ/VZ1UjSlFWnCjT0CR0tnXsPmlIaC98HThS8x5zNB -fvvSN+Zln8RWdNLnEVHVdqYtOQ828QbCx8s1HfClGgaVoSDrzz+qQgtZFO4wW264 -2CWkNd8DSJUJ/HlPNXmbXsrRMgvGaL7YUz2yRQIDAQABo0AwPjAJBgNVHRMEAjAA -MAsGA1UdDwQEAwIFIDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHREECDAGhwR/ -AAABMA0GCSqGSIb3DQEBBQUAA4IBAQAE2g+wAFf9Xg5svcnb7+mfseYV16k9l5WG -onrmR3FLsbTxfbr4PZJMHrswPbi2NRk0+ETPUpcv1RP7pUB7wSEvuS1NPGcU92iP -58ycP3dYtLzmuu6BkgToZqwsCU8fC2zM0wt3+ifzPpDMffWWOioVuA3zdM9WPQYz -+Ofajd0XaZwFZS8uTI5WXgObz7Xqfmln4tF3Sq1CTyuJ44qK4p83XOKFq+L04aD0 -d0c8w3YQNUENny/vMP9mDu3FQ3SnDz2GKl1LSjGe2TUnkoMkDfdk4wSzndTz/ecb -QiCPKijwVPWNOWV3NDE2edMxDPxDoKoEm5F4UGfGjxSRnYCIoZLh ------END CERTIFICATE----- -` - -const serverKey = ` ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAxYAKbeGyg0gP0xwVsZsufzk/SUCtD44Gp3lQYQ9QumQ1IVZu -PmZWwPWrzI93a1Abruz6ZhXaB3jcL5QPAy1N44IiFgVN45CZXBsqkpJe/abzRFOV -DRnHxattPDHdgwML5d3nURKGUM/7+ACj5E4pZEDlM3RIjIKVd+doJsL7n6myO8FE -tIpt4vTz1MFp3F+ntPnHU3BZ/VZ1UjSlFWnCjT0CR0tnXsPmlIaC98HThS8x5zNB -fvvSN+Zln8RWdNLnEVHVdqYtOQ828QbCx8s1HfClGgaVoSDrzz+qQgtZFO4wW264 -2CWkNd8DSJUJ/HlPNXmbXsrRMgvGaL7YUz2yRQIDAQABAoIBAGsyEvcPAGg3DbfE -z5WFp9gPx2TIAOanbL8rnlAAEw4H47qDgfTGcSHsdeHioKuTYGMyZrpP8/YISGJe -l0NfLJ5mfH+9Q0hXrJWMfS/u2DYOjo0wXH8u1fpZEEISwqsgVS3fonSjfFmSea1j -E5GQRvEONBkYbWQuYFgjNqmLPS2r5lKbWCQvc1MB/vvVBwOTiO0ON7m/EkM5RKt9 -cDT5ZhhVjBpdmd9HpVbKTdBj8Q0l5/ZHZUEgZA6FDZEwYxTd9l87Z4YT+5SR0z9t -k8/Z0CHd3x3Rv891t7m66ZJkaOda8NC65/432MQEQwJltmrKnc22dS8yI26rrmpp -g3tcbSUCgYEA5nMXdQKS4vF+Kp10l/HqvGz2sU8qQaWYZQIg7Th3QJPo6N52po/s -nn3UF0P5mT1laeZ5ZQJKx4gnmuPnIZ2ZtJQDyFhIbRPcZ+2hSNSuLYVcrumOC3EP -3OZyFtFE1THO73aFe5e1jEdtoOne3Bds/Hq6NF45fkVdL+M9e8pfXIsCgYEA22W8 -zGjbWyrFOYvKknMQVtHnMx8BJEtsvWRknP6CWAv/8WyeZpE128Pve1m441AQnopS -CuOF5wFK0iUXBFbS3Pe1/1j3em6yfVznuUHqJ7Qc+dNzxVvkTK8jGB6x+vm+M9Hg -muHUM726IUxckoSNXbPNAVPIZab1NdSxam7F9m8CgYEAx55QZmIJXJ41XLKxqWC7 -peZ5NpPNlbncrTpPzUzJN94ntXfmrVckbxGt401VayEctMQYyZ9XqUlOjUP3FU5Q -M3S3Zhba/eljVX8o406fZf0MkNLs4QpZ5E6V6x/xEP+pMhKng6yhbVb+JpIPIvUD -yhyBKRWplbB+DRo5Sv685gsCgYA7l5m9h+m1DJv/cnn2Z2yTuHXtC8namuYRV1iA -0ByFX9UINXGc+GpBpCnDPm6ax5+MAJQiQwSW52H0TIDA+/hQbrQvhHHL/o9av8Zt -Kns4h5KrRQUYIUqUjamhnozHV9iS6LnyN87Usv8AlmY6oehoADN53dD702qdUYVT -HH2G3wKBgCdvqyw78FR/n8cUWesTPnxx5HCeWJ1J+2BESnUnPmKZ71CV1H7uweja -vPUxuuuGLKfNx84OKCfRDbtOgMOeyh9T1RmXry6Srz/7/udjlF0qmFiRXfBNAgoR -tNb0+Ri/vY0AHrQ7UnCbl12qPVaqhEXLr+kCGNEPFqpMJPPEeMK0 ------END RSA PRIVATE KEY----- -` - -const clientCert = ` ------BEGIN CERTIFICATE----- -MIIC4jCCAcqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl -c3RDQTAeFw0xNDAxMjcxOTUyMjNaFw0yNDAxMjUxOTUyMjNaMCUxEjAQBgNVBAMT -CTEyNy4wLjAuMTEPMA0GA1UEChMGY2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAu7LMqd+agoH168Bsi0WJ36ulYqDypq+GZPF7uWOo2pE0raKH -B++31/hjnkt6yC5kLKVZZ0EfolBa9q4Cy6swfGaEMafy44ZCRneLnt1azL1N6Kfz -+U0KsOqyQDoMxYJG1gVTEZN19/U/ew2eazcxKyERI3oGCQ4SbpkxBTbfxtAFk49e -xIB3obsuMVUrmtXE4FkUkvG7NgpPUgrhp0yxYpj9zruZGzGGT1zNhcarbQ/4i7It -ZMbnv6pqQWtYDgnGX2TDRcEiXGeO+KrzhfpTRLfO3K4np8e8cmTyXM+4lMlWUgma -KrRdu1QXozGqRs47u2prGKGdSQWITpqNVCY8fQIDAQABoy8wLTAJBgNVHRMEAjAA -MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQUF -AAOCAQEAhCuBCLznPc4O96hT3P8Fx19L3ltrWbc/pWrx8JjxUaGk8kNmjMjY+/Mt -JBbjUBx2kJwaY0EHMAfw7D1f1wcCeNycx/0dyb0E6xzhmPw5fY15GGNg8rzWwqSY -+i/1iqU0IRkmRHV7XCF+trd2H0Ec+V1Fd/61E2ccJfOL5aSAyWbMCUtWxS3QMnqH -FBfKdVEiY9WNht5hnvsXQBRaNhowJ6Cwa7/1/LZjmhcXiJ0xrc1Hggj3cvS+4vll -Ew+20a0tPKjD/v/2oSQL+qkeYKV4fhCGkaBHCpPlSJrqorb7B6NmPy3nS26ETKE/ -o2UCfZc5g2MU1ENa31kT1iuhKZapsA== ------END CERTIFICATE----- -` - -const clientKey = ` ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAu7LMqd+agoH168Bsi0WJ36ulYqDypq+GZPF7uWOo2pE0raKH -B++31/hjnkt6yC5kLKVZZ0EfolBa9q4Cy6swfGaEMafy44ZCRneLnt1azL1N6Kfz -+U0KsOqyQDoMxYJG1gVTEZN19/U/ew2eazcxKyERI3oGCQ4SbpkxBTbfxtAFk49e -xIB3obsuMVUrmtXE4FkUkvG7NgpPUgrhp0yxYpj9zruZGzGGT1zNhcarbQ/4i7It -ZMbnv6pqQWtYDgnGX2TDRcEiXGeO+KrzhfpTRLfO3K4np8e8cmTyXM+4lMlWUgma -KrRdu1QXozGqRs47u2prGKGdSQWITpqNVCY8fQIDAQABAoIBAGSEn3hFyEAmCyYi -2b5IEksXaC2GlgxQKb/7Vs/0oCPU6YonZPsKFMFzQx4tu+ZiecEzF8rlJGTPdbdv -fw3FcuTcHeVd1QSmDO4h7UK5tnu40XVMJKsY6CXQun8M13QajYbmORNLjjypOULU -C0fNueYoAj6mhX7p61MRdSAev/5+0+bVQQG/tSVDQzdngvKpaCunOphiB2VW2Aa0 -7aYPOFCoPB2uo0DwUmBB0yfx9x4hXX9ovQI0YFou7bq6iYJ0vlZBvYQ9YrVdxjKL -avcz1N5xM3WFAkZJSVT/Ho5+uTbZx4RrJ8b5T+t2spOKmXyAjwS2rL/XMAh8YRZ1 -u44duoECgYEA4jpK2qshgQ0t49rjVHEDKX5x7ElEZefl0rHZ/2X/uHUDKpKj2fTq -3TQzHquiQ4Aof7OEB9UE3DGrtpvo/j/PYxL5Luu5VR4AIEJm+CA8GYuE96+uIL0Z -M2r3Lux6Bp30Z47Eit2KiY4fhrWs59WB3NHHoFxgzHSVbnuA02gcX2ECgYEA1GZw -iXIVYaK07ED+q/0ObyS5hD1cMhJ7ifSN9BxuG0qUpSigbkTGj09fUDS4Fqsz9dvz -F0P93fZvyia242TIfDUwJEsDQCgHk7SGa4Rx/p/3x/obIEERk7K76Hdg93U5NXhV -NvczvgL0HYxnb+qtumwMgGPzncB4lGcTnRyOfp0CgYBTIsDnYwRI/KLknUf1fCKB -WSpcfwBXwsS+jQVjygQTsUyclI8KResZp1kx6DkVPT+kzj+y8SF8GfTUgq844BJC -gnJ4P8A3+3JoaH6WqKHtcUxICZOgDF36e1CjOdwOGnX6qIipz4hdzJDhXFpSSDAV -CjKmR8x61k0j8NcC2buzgQKBgFr7eo9VwBTvpoJhIPY5UvqHB7S+uAR26FZi3H/J -wdyM6PmKWpaBfXCb9l8cBhMnyP0y94FqzY9L5fz48nSbkkmqWvHg9AaCXySFOuNJ -e68vhOszlnUNimLzOAzPPkkh/JyL7Cy8XXyyNTGHGDPXmg12BTDmH8/eR4iCUuOE -/QD9AoGBALQ/SkvfO3D5+k9e/aTHRuMJ0+PWdLUMTZ39oJQxUx+qj7/xpjDvWTBn -eDmF/wjnIAg+020oXyBYo6plEZfDz3EYJQZ+3kLLEU+O/A7VxCakPYPwCr7N/InL -Ccg/TVSIXxw/6uJnojoAjMIEU45NoP6RMp0mWYYb2OlteEv08Ovp ------END RSA PRIVATE KEY----- -` diff --git a/vendor/github.com/streadway/amqp/types.go b/vendor/github.com/streadway/amqp/types.go deleted file mode 100644 index 6566198cea7..00000000000 --- a/vendor/github.com/streadway/amqp/types.go +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -package amqp - -import ( - "fmt" - "io" - "time" -) - -var ( - // Errors that this library could return/emit from a channel or connection - ErrClosed = &Error{Code: ChannelError, Reason: "channel/connection is not open"} - ErrChannelMax = &Error{Code: ChannelError, Reason: "channel id space exhausted"} - ErrSASL = &Error{Code: AccessRefused, Reason: "SASL could not negotiate a shared mechanism"} - ErrCredentials = &Error{Code: AccessRefused, Reason: "username or password not allowed"} - ErrVhost = &Error{Code: AccessRefused, Reason: "no access to this vhost"} - ErrSyntax = &Error{Code: SyntaxError, Reason: "invalid field or value inside of a frame"} - ErrFrame = &Error{Code: FrameError, Reason: "frame could not be parsed"} - ErrCommandInvalid = &Error{Code: CommandInvalid, Reason: "unexpected command received"} - ErrUnexpectedFrame = &Error{Code: UnexpectedFrame, Reason: "unexpected frame received"} - ErrFieldType = &Error{Code: SyntaxError, Reason: "unsupported table field type"} -) - -// Error captures the code and reason a channel or connection has been closed -// by the server. -type Error struct { - Code int // constant code from the specification - Reason string // description of the error - Server bool // true when initiated from the server, false when from this library - Recover bool // true when this error can be recovered by retrying later or with differnet parameters -} - -func newError(code uint16, text string) *Error { - return &Error{ - Code: int(code), - Reason: text, - Recover: isSoftExceptionCode(int(code)), - Server: true, - } -} - -func (me Error) Error() string { - return fmt.Sprintf("Exception (%d) Reason: %q", me.Code, me.Reason) -} - -// Used by header frames to capture routing and header information -type properties struct { - ContentType string // MIME content type - ContentEncoding string // MIME content encoding - Headers Table // Application or header exchange table - DeliveryMode uint8 // queue implemention use - Transient (1) or Persistent (2) - Priority uint8 // queue implementation use - 0 to 9 - CorrelationId string // application use - correlation identifier - ReplyTo string // application use - address to to reply to (ex: RPC) - Expiration string // implementation use - message expiration spec - MessageId string // application use - message identifier - Timestamp time.Time // application use - message timestamp - Type string // application use - message type name - UserId string // application use - creating user id - AppId string // application use - creating application - reserved1 string // was cluster-id - process for buffer consumption -} - -// DeliveryMode. Transient means higher throughput but messages will not be -// restored on broker restart. The delivery mode of publishings is unrelated -// to the durability of the queues they reside on. Transient messages will -// not be restored to durable queues, persistent messages will be restored to -// durable queues and lost on non-durable queues during server restart. -// -// This remains typed as uint8 to match Publishing.DeliveryMode. Other -// delivery modes specific to custom queue implementations are not enumerated -// here. -const ( - Transient uint8 = 1 - Persistent uint8 = 2 -) - -// The property flags are an array of bits that indicate the presence or -// absence of each property value in sequence. The bits are ordered from most -// high to low - bit 15 indicates the first property. -const ( - flagContentType = 0x8000 - flagContentEncoding = 0x4000 - flagHeaders = 0x2000 - flagDeliveryMode = 0x1000 - flagPriority = 0x0800 - flagCorrelationId = 0x0400 - flagReplyTo = 0x0200 - flagExpiration = 0x0100 - flagMessageId = 0x0080 - flagTimestamp = 0x0040 - flagType = 0x0020 - flagUserId = 0x0010 - flagAppId = 0x0008 - flagReserved1 = 0x0004 -) - -// Queue captures the current server state of the queue on the server returned -// from Channel.QueueDeclare or Channel.QueueInspect. -type Queue struct { - Name string // server confirmed or generated name - Messages int // count of messages not awaiting acknowledgment - Consumers int // number of consumers receiving deliveries -} - -// Publishing captures the client message sent to the server. The fields -// outside of the Headers table included in this struct mirror the underlying -// fields in the content frame. They use native types for convenience and -// efficiency. -type Publishing struct { - // Application or exchange specific fields, - // the headers exchange will inspect this field. - Headers Table - - // Properties - ContentType string // MIME content type - ContentEncoding string // MIME content encoding - DeliveryMode uint8 // Transient (0 or 1) or Persistent (2) - Priority uint8 // 0 to 9 - CorrelationId string // correlation identifier - ReplyTo string // address to to reply to (ex: RPC) - Expiration string // message expiration spec - MessageId string // message identifier - Timestamp time.Time // message timestamp - Type string // message type name - UserId string // creating user id - ex: "guest" - AppId string // creating application id - - // The application specific payload of the message - Body []byte -} - -// Blocking notifies the server's TCP flow control of the Connection. When a -// server hits a memory or disk alarm it will block all connections until the -// resources are reclaimed. Use NotifyBlock on the Connection to receive these -// events. -type Blocking struct { - Active bool // TCP pushback active/inactive on server - Reason string // Server reason for activation -} - -// Decimal matches the AMQP decimal type. Scale is the number of decimal -// digits Scale == 2, Value == 12345, Decimal == 123.45 -type Decimal struct { - Scale uint8 - Value int32 -} - -// Table stores user supplied fields of the following types: -// -// bool -// byte -// float32 -// float64 -// int16 -// int32 -// int64 -// nil -// string -// time.Time -// amqp.Decimal -// amqp.Table -// []byte -// []interface{} - containing above types -// -// Functions taking a table will immediately fail when the table contains a -// value of an unsupported type. -// -// The caller must be specific in which precision of integer it wishes to -// encode. -// -// Use a type assertion when reading values from a table for type converstion. -// -// RabbitMQ expects int32 for integer values. -// -type Table map[string]interface{} - -func validateField(f interface{}) error { - switch fv := f.(type) { - case nil, bool, byte, int16, int32, int64, float32, float64, string, []byte, Decimal, time.Time: - return nil - - case []interface{}: - for _, v := range fv { - if err := validateField(v); err != nil { - return fmt.Errorf("in array %s", err) - } - } - return nil - - case Table: - for k, v := range fv { - if err := validateField(v); err != nil { - return fmt.Errorf("table field %q %s", k, err) - } - } - return nil - } - - return fmt.Errorf("value %t not supported", f) -} - -func (t Table) Validate() error { - return validateField(t) -} - -// Heap interface for maintaining delivery tags -type tagSet []uint64 - -func (me tagSet) Len() int { return len(me) } -func (me tagSet) Less(i, j int) bool { return (me)[i] < (me)[j] } -func (me tagSet) Swap(i, j int) { (me)[i], (me)[j] = (me)[j], (me)[i] } -func (me *tagSet) Push(tag interface{}) { *me = append(*me, tag.(uint64)) } -func (me *tagSet) Pop() interface{} { - val := (*me)[len(*me)-1] - *me = (*me)[:len(*me)-1] - return val -} - -type message interface { - id() (uint16, uint16) - wait() bool - read(io.Reader) error - write(io.Writer) error -} - -type messageWithContent interface { - message - getContent() (properties, []byte) - setContent(properties, []byte) -} - -/* -The base interface implemented as: - -2.3.5 frame Details - -All frames consist of a header (7 octets), a payload of arbitrary size, and a 'frame-end' octet that detects -malformed frames: - - 0 1 3 7 size+7 size+8 - +------+---------+-------------+ +------------+ +-----------+ - | type | channel | size | | payload | | frame-end | - +------+---------+-------------+ +------------+ +-----------+ - octet short long size octets octet - -To read a frame, we: - - 1. Read the header and check the frame type and channel. - 2. Depending on the frame type, we read the payload and process it. - 3. Read the frame end octet. - -In realistic implementations where performance is a concern, we would use -“read-ahead buffering” or “gathering reads” to avoid doing three separate -system calls to read a frame. - -*/ -type frame interface { - write(io.Writer) error - channel() uint16 -} - -type reader struct { - r io.Reader -} - -type writer struct { - w io.Writer -} - -// Implements the frame interface for Connection RPC -type protocolHeader struct{} - -func (protocolHeader) write(w io.Writer) error { - _, err := w.Write([]byte{'A', 'M', 'Q', 'P', 0, 0, 9, 1}) - return err -} - -func (protocolHeader) channel() uint16 { - panic("only valid as initial handshake") -} - -/* -Method frames carry the high-level protocol commands (which we call "methods"). -One method frame carries one command. The method frame payload has this format: - - 0 2 4 - +----------+-----------+-------------- - - - | class-id | method-id | arguments... - +----------+-----------+-------------- - - - short short ... - -To process a method frame, we: - 1. Read the method frame payload. - 2. Unpack it into a structure. A given method always has the same structure, - so we can unpack the method rapidly. 3. Check that the method is allowed in - the current context. - 4. Check that the method arguments are valid. - 5. Execute the method. - -Method frame bodies are constructed as a list of AMQP data fields (bits, -integers, strings and string tables). The marshalling code is trivially -generated directly from the protocol specifications, and can be very rapid. -*/ -type methodFrame struct { - ChannelId uint16 - ClassId uint16 - MethodId uint16 - Method message -} - -func (me *methodFrame) channel() uint16 { return me.ChannelId } - -/* -Heartbeating is a technique designed to undo one of TCP/IP's features, namely -its ability to recover from a broken physical connection by closing only after -a quite long time-out. In some scenarios we need to know very rapidly if a -peer is disconnected or not responding for other reasons (e.g. it is looping). -Since heartbeating can be done at a low level, we implement this as a special -type of frame that peers exchange at the transport level, rather than as a -class method. -*/ -type heartbeatFrame struct { - ChannelId uint16 -} - -func (me *heartbeatFrame) channel() uint16 { return me.ChannelId } - -/* -Certain methods (such as Basic.Publish, Basic.Deliver, etc.) are formally -defined as carrying content. When a peer sends such a method frame, it always -follows it with a content header and zero or more content body frames. - -A content header frame has this format: - - 0 2 4 12 14 - +----------+--------+-----------+----------------+------------- - - - | class-id | weight | body size | property flags | property list... - +----------+--------+-----------+----------------+------------- - - - short short long long short remainder... - -We place content body in distinct frames (rather than including it in the -method) so that AMQP may support "zero copy" techniques in which content is -never marshalled or encoded. We place the content properties in their own -frame so that recipients can selectively discard contents they do not want to -process -*/ -type headerFrame struct { - ChannelId uint16 - ClassId uint16 - weight uint16 - Size uint64 - Properties properties -} - -func (me *headerFrame) channel() uint16 { return me.ChannelId } - -/* -Content is the application data we carry from client-to-client via the AMQP -server. Content is, roughly speaking, a set of properties plus a binary data -part. The set of allowed properties are defined by the Basic class, and these -form the "content header frame". The data can be any size, and MAY be broken -into several (or many) chunks, each forming a "content body frame". - -Looking at the frames for a specific channel, as they pass on the wire, we -might see something like this: - - [method] - [method] [header] [body] [body] - [method] - ... -*/ -type bodyFrame struct { - ChannelId uint16 - Body []byte -} - -func (me *bodyFrame) channel() uint16 { return me.ChannelId } diff --git a/vendor/github.com/streadway/amqp/uri.go b/vendor/github.com/streadway/amqp/uri.go deleted file mode 100644 index 582464db576..00000000000 --- a/vendor/github.com/streadway/amqp/uri.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -package amqp - -import ( - "errors" - "fmt" - "net/url" - "strconv" - "strings" -) - -var errURIScheme = errors.New("AMQP scheme must be either 'amqp://' or 'amqps://'") - -var schemePorts = map[string]int{ - "amqp": 5672, - "amqps": 5671, -} - -var defaultURI = URI{ - Scheme: "amqp", - Host: "localhost", - Port: 5672, - Username: "guest", - Password: "guest", - Vhost: "/", -} - -// URI represents a parsed AMQP URI string. -type URI struct { - Scheme string - Host string - Port int - Username string - Password string - Vhost string -} - -// ParseURI attempts to parse the given AMQP URI according to the spec. -// See http://www.rabbitmq.com/uri-spec.html. -// -// Default values for the fields are: -// -// Scheme: amqp -// Host: localhost -// Port: 5672 -// Username: guest -// Password: guest -// Vhost: / -// -func ParseURI(uri string) (URI, error) { - me := defaultURI - - u, err := url.Parse(uri) - if err != nil { - return me, err - } - - defaultPort, okScheme := schemePorts[u.Scheme] - - if okScheme { - me.Scheme = u.Scheme - } else { - return me, errURIScheme - } - - host, port := splitHostPort(u.Host) - - if host != "" { - me.Host = host - } - - if port != "" { - port32, err := strconv.ParseInt(port, 10, 32) - if err != nil { - return me, err - } - me.Port = int(port32) - } else { - me.Port = defaultPort - } - - if u.User != nil { - me.Username = u.User.Username() - if password, ok := u.User.Password(); ok { - me.Password = password - } - } - - if u.Path != "" { - if strings.HasPrefix(u.Path, "/") { - if u.Host == "" && strings.HasPrefix(u.Path, "///") { - // net/url doesn't handle local context authorities and leaves that up - // to the scheme handler. In our case, we translate amqp:/// into the - // default host and whatever the vhost should be - if len(u.Path) > 3 { - me.Vhost = u.Path[3:] - } - } else if len(u.Path) > 1 { - me.Vhost = u.Path[1:] - } - } else { - me.Vhost = u.Path - } - } - - return me, nil -} - -// Splits host:port, host, [ho:st]:port, or [ho:st]. Unlike net.SplitHostPort -// which splits :port, host:port or [host]:port -// -// Handles hosts that have colons that are in brackets like [::1]:http -func splitHostPort(addr string) (host, port string) { - i := strings.LastIndex(addr, ":") - - if i >= 0 { - host, port = addr[:i], addr[i+1:] - - if len(port) > 0 && port[len(port)-1] == ']' && addr[0] == '[' { - // we've split on an inner colon, the port was missing outside of the - // brackets so use the full addr. We could assert that host should not - // contain any colons here - host, port = addr, "" - } - } else { - host = addr - } - - return -} - -// PlainAuth returns a PlainAuth structure based on the parsed URI's -// Username and Password fields. -func (me URI) PlainAuth() *PlainAuth { - return &PlainAuth{ - Username: me.Username, - Password: me.Password, - } -} - -func (me URI) String() string { - var authority string - - if me.Username != defaultURI.Username || me.Password != defaultURI.Password { - authority += me.Username - - if me.Password != defaultURI.Password { - authority += ":" + me.Password - } - - authority += "@" - } - - authority += me.Host - - if defaultPort, found := schemePorts[me.Scheme]; !found || defaultPort != me.Port { - authority += ":" + strconv.FormatInt(int64(me.Port), 10) - } - - var vhost string - if me.Vhost != defaultURI.Vhost { - vhost = me.Vhost - } - - return fmt.Sprintf("%s://%s/%s", me.Scheme, authority, url.QueryEscape(vhost)) -} diff --git a/vendor/github.com/streadway/amqp/uri_test.go b/vendor/github.com/streadway/amqp/uri_test.go deleted file mode 100644 index 5d93e0bc73d..00000000000 --- a/vendor/github.com/streadway/amqp/uri_test.go +++ /dev/null @@ -1,328 +0,0 @@ -package amqp - -import ( - "testing" -) - -// Test matrix defined on http://www.rabbitmq.com/uri-spec.html -type testURI struct { - url string - username string - password string - host string - port int - vhost string - canon string -} - -var uriTests = []testURI{ - { - url: "amqp://user:pass@host:10000/vhost", - username: "user", - password: "pass", - host: "host", - port: 10000, - vhost: "vhost", - canon: "amqp://user:pass@host:10000/vhost", - }, - - // this fails due to net/url not parsing pct-encoding in host - // testURI{url: "amqp://user%61:%61pass@ho%61st:10000/v%2Fhost", - // username: "usera", - // password: "apass", - // host: "hoast", - // port: 10000, - // vhost: "v/host", - // }, - - { - url: "amqp://", - username: defaultURI.Username, - password: defaultURI.Password, - host: defaultURI.Host, - port: defaultURI.Port, - vhost: defaultURI.Vhost, - canon: "amqp://localhost/", - }, - - { - url: "amqp://:@/", - username: "", - password: "", - host: defaultURI.Host, - port: defaultURI.Port, - vhost: defaultURI.Vhost, - canon: "amqp://:@localhost/", - }, - - { - url: "amqp://user@", - username: "user", - password: defaultURI.Password, - host: defaultURI.Host, - port: defaultURI.Port, - vhost: defaultURI.Vhost, - canon: "amqp://user@localhost/", - }, - - { - url: "amqp://user:pass@", - username: "user", - password: "pass", - host: defaultURI.Host, - port: defaultURI.Port, - vhost: defaultURI.Vhost, - canon: "amqp://user:pass@localhost/", - }, - - { - url: "amqp://guest:pass@", - username: "guest", - password: "pass", - host: defaultURI.Host, - port: defaultURI.Port, - vhost: defaultURI.Vhost, - canon: "amqp://guest:pass@localhost/", - }, - - { - url: "amqp://host", - username: defaultURI.Username, - password: defaultURI.Password, - host: "host", - port: defaultURI.Port, - vhost: defaultURI.Vhost, - canon: "amqp://host/", - }, - - { - url: "amqp://:10000", - username: defaultURI.Username, - password: defaultURI.Password, - host: defaultURI.Host, - port: 10000, - vhost: defaultURI.Vhost, - canon: "amqp://localhost:10000/", - }, - - { - url: "amqp:///vhost", - username: defaultURI.Username, - password: defaultURI.Password, - host: defaultURI.Host, - port: defaultURI.Port, - vhost: "vhost", - canon: "amqp://localhost/vhost", - }, - - { - url: "amqp://host/", - username: defaultURI.Username, - password: defaultURI.Password, - host: "host", - port: defaultURI.Port, - vhost: defaultURI.Vhost, - canon: "amqp://host/", - }, - - { - url: "amqp://host/%2F", - username: defaultURI.Username, - password: defaultURI.Password, - host: "host", - port: defaultURI.Port, - vhost: "/", - canon: "amqp://host/", - }, - - { - url: "amqp://host/%2F%2F", - username: defaultURI.Username, - password: defaultURI.Password, - host: "host", - port: defaultURI.Port, - vhost: "//", - canon: "amqp://host/%2F%2F", - }, - - { - url: "amqp://host/%2Fslash%2F", - username: defaultURI.Username, - password: defaultURI.Password, - host: "host", - port: defaultURI.Port, - vhost: "/slash/", - canon: "amqp://host/%2Fslash%2F", - }, - - { - url: "amqp://192.168.1.1:1000/", - username: defaultURI.Username, - password: defaultURI.Password, - host: "192.168.1.1", - port: 1000, - vhost: defaultURI.Vhost, - canon: "amqp://192.168.1.1:1000/", - }, - - { - url: "amqp://[::1]", - username: defaultURI.Username, - password: defaultURI.Password, - host: "[::1]", - port: defaultURI.Port, - vhost: defaultURI.Vhost, - canon: "amqp://[::1]/", - }, - - { - url: "amqp://[::1]:1000", - username: defaultURI.Username, - password: defaultURI.Password, - host: "[::1]", - port: 1000, - vhost: defaultURI.Vhost, - canon: "amqp://[::1]:1000/", - }, - - { - url: "amqps:///", - username: defaultURI.Username, - password: defaultURI.Password, - host: defaultURI.Host, - port: schemePorts["amqps"], - vhost: defaultURI.Vhost, - canon: "amqps://localhost/", - }, - - { - url: "amqps://host:1000/", - username: defaultURI.Username, - password: defaultURI.Password, - host: "host", - port: 1000, - vhost: defaultURI.Vhost, - canon: "amqps://host:1000/", - }, -} - -func TestURISpec(t *testing.T) { - for _, test := range uriTests { - u, err := ParseURI(test.url) - if err != nil { - t.Fatal("Could not parse spec URI: ", test.url, " err: ", err) - } - - if test.username != u.Username { - t.Error("For: ", test.url, " usernames do not match. want: ", test.username, " got: ", u.Username) - } - - if test.password != u.Password { - t.Error("For: ", test.url, " passwords do not match. want: ", test.password, " got: ", u.Password) - } - - if test.host != u.Host { - t.Error("For: ", test.url, " hosts do not match. want: ", test.host, " got: ", u.Host) - } - - if test.port != u.Port { - t.Error("For: ", test.url, " ports do not match. want: ", test.port, " got: ", u.Port) - } - - if test.vhost != u.Vhost { - t.Error("For: ", test.url, " vhosts do not match. want: ", test.vhost, " got: ", u.Vhost) - } - - if test.canon != u.String() { - t.Error("For: ", test.url, " canonical string does not match. want: ", test.canon, " got: ", u.String()) - } - } -} - -func TestURIUnknownScheme(t *testing.T) { - if _, err := ParseURI("http://example.com/"); err == nil { - t.Fatal("Expected error when parsing non-amqp scheme") - } -} - -func TestURIScheme(t *testing.T) { - if _, err := ParseURI("amqp://example.com/"); err != nil { - t.Fatalf("Expected to parse amqp scheme, got %v", err) - } - - if _, err := ParseURI("amqps://example.com/"); err != nil { - t.Fatalf("Expected to parse amqps scheme, got %v", err) - } -} - -func TestURIDefaults(t *testing.T) { - url := "amqp://" - uri, err := ParseURI(url) - if err != nil { - t.Fatal("Could not parse") - } - - if uri.String() != "amqp://localhost/" { - t.Fatal("Defaults not encoded properly got:", uri.String()) - } -} - -func TestURIComplete(t *testing.T) { - url := "amqp://bob:dobbs@foo.bar:5678/private" - uri, err := ParseURI(url) - if err != nil { - t.Fatal("Could not parse") - } - - if uri.String() != url { - t.Fatal("Defaults not encoded properly want:", url, " got:", uri.String()) - } -} - -func TestURIDefaultPortAmqpNotIncluded(t *testing.T) { - url := "amqp://foo.bar:5672/" - uri, err := ParseURI(url) - if err != nil { - t.Fatal("Could not parse") - } - - if uri.String() != "amqp://foo.bar/" { - t.Fatal("Defaults not encoded properly got:", uri.String()) - } -} - -func TestURIDefaultPortAmqp(t *testing.T) { - url := "amqp://foo.bar/" - uri, err := ParseURI(url) - if err != nil { - t.Fatal("Could not parse") - } - - if uri.Port != 5672 { - t.Fatal("Default port not correct for amqp, got:", uri.Port) - } -} - -func TestURIDefaultPortAmqpsNotIncludedInString(t *testing.T) { - url := "amqps://foo.bar:5671/" - uri, err := ParseURI(url) - if err != nil { - t.Fatal("Could not parse") - } - - if uri.String() != "amqps://foo.bar/" { - t.Fatal("Defaults not encoded properly got:", uri.String()) - } -} - -func TestURIDefaultPortAmqps(t *testing.T) { - url := "amqps://foo.bar/" - uri, err := ParseURI(url) - if err != nil { - t.Fatal("Could not parse") - } - - if uri.Port != 5671 { - t.Fatal("Default port not correct for amqps, got:", uri.Port) - } -} diff --git a/vendor/github.com/streadway/amqp/write.go b/vendor/github.com/streadway/amqp/write.go deleted file mode 100644 index d392ca237b7..00000000000 --- a/vendor/github.com/streadway/amqp/write.go +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -package amqp - -import ( - "bufio" - "bytes" - "encoding/binary" - "errors" - "io" - "math" - "time" -) - -func (me *writer) WriteFrame(frame frame) (err error) { - if err = frame.write(me.w); err != nil { - return - } - - if buf, ok := me.w.(*bufio.Writer); ok { - err = buf.Flush() - } - - return -} - -func (me *methodFrame) write(w io.Writer) (err error) { - var payload bytes.Buffer - - if me.Method == nil { - return errors.New("malformed frame: missing method") - } - - class, method := me.Method.id() - - if err = binary.Write(&payload, binary.BigEndian, class); err != nil { - return - } - - if err = binary.Write(&payload, binary.BigEndian, method); err != nil { - return - } - - if err = me.Method.write(&payload); err != nil { - return - } - - return writeFrame(w, frameMethod, me.ChannelId, payload.Bytes()) -} - -// Heartbeat -// -// Payload is empty -func (me *heartbeatFrame) write(w io.Writer) (err error) { - return writeFrame(w, frameHeartbeat, me.ChannelId, []byte{}) -} - -// CONTENT HEADER -// 0 2 4 12 14 -// +----------+--------+-----------+----------------+------------- - - -// | class-id | weight | body size | property flags | property list... -// +----------+--------+-----------+----------------+------------- - - -// short short long long short remainder... -// -func (me *headerFrame) write(w io.Writer) (err error) { - var payload bytes.Buffer - var zeroTime time.Time - - if err = binary.Write(&payload, binary.BigEndian, me.ClassId); err != nil { - return - } - - if err = binary.Write(&payload, binary.BigEndian, me.weight); err != nil { - return - } - - if err = binary.Write(&payload, binary.BigEndian, me.Size); err != nil { - return - } - - // First pass will build the mask to be serialized, second pass will serialize - // each of the fields that appear in the mask. - - var mask uint16 - - if len(me.Properties.ContentType) > 0 { - mask = mask | flagContentType - } - if len(me.Properties.ContentEncoding) > 0 { - mask = mask | flagContentEncoding - } - if me.Properties.Headers != nil && len(me.Properties.Headers) > 0 { - mask = mask | flagHeaders - } - if me.Properties.DeliveryMode > 0 { - mask = mask | flagDeliveryMode - } - if me.Properties.Priority > 0 { - mask = mask | flagPriority - } - if len(me.Properties.CorrelationId) > 0 { - mask = mask | flagCorrelationId - } - if len(me.Properties.ReplyTo) > 0 { - mask = mask | flagReplyTo - } - if len(me.Properties.Expiration) > 0 { - mask = mask | flagExpiration - } - if len(me.Properties.MessageId) > 0 { - mask = mask | flagMessageId - } - if me.Properties.Timestamp != zeroTime { - mask = mask | flagTimestamp - } - if len(me.Properties.Type) > 0 { - mask = mask | flagType - } - if len(me.Properties.UserId) > 0 { - mask = mask | flagUserId - } - if len(me.Properties.AppId) > 0 { - mask = mask | flagAppId - } - - if err = binary.Write(&payload, binary.BigEndian, mask); err != nil { - return - } - - if hasProperty(mask, flagContentType) { - if err = writeShortstr(&payload, me.Properties.ContentType); err != nil { - return - } - } - if hasProperty(mask, flagContentEncoding) { - if err = writeShortstr(&payload, me.Properties.ContentEncoding); err != nil { - return - } - } - if hasProperty(mask, flagHeaders) { - if err = writeTable(&payload, me.Properties.Headers); err != nil { - return - } - } - if hasProperty(mask, flagDeliveryMode) { - if err = binary.Write(&payload, binary.BigEndian, me.Properties.DeliveryMode); err != nil { - return - } - } - if hasProperty(mask, flagPriority) { - if err = binary.Write(&payload, binary.BigEndian, me.Properties.Priority); err != nil { - return - } - } - if hasProperty(mask, flagCorrelationId) { - if err = writeShortstr(&payload, me.Properties.CorrelationId); err != nil { - return - } - } - if hasProperty(mask, flagReplyTo) { - if err = writeShortstr(&payload, me.Properties.ReplyTo); err != nil { - return - } - } - if hasProperty(mask, flagExpiration) { - if err = writeShortstr(&payload, me.Properties.Expiration); err != nil { - return - } - } - if hasProperty(mask, flagMessageId) { - if err = writeShortstr(&payload, me.Properties.MessageId); err != nil { - return - } - } - if hasProperty(mask, flagTimestamp) { - if err = binary.Write(&payload, binary.BigEndian, uint64(me.Properties.Timestamp.Unix())); err != nil { - return - } - } - if hasProperty(mask, flagType) { - if err = writeShortstr(&payload, me.Properties.Type); err != nil { - return - } - } - if hasProperty(mask, flagUserId) { - if err = writeShortstr(&payload, me.Properties.UserId); err != nil { - return - } - } - if hasProperty(mask, flagAppId) { - if err = writeShortstr(&payload, me.Properties.AppId); err != nil { - return - } - } - - return writeFrame(w, frameHeader, me.ChannelId, payload.Bytes()) -} - -// Body -// -// Payload is one byterange from the full body who's size is declared in the -// Header frame -func (me *bodyFrame) write(w io.Writer) (err error) { - return writeFrame(w, frameBody, me.ChannelId, me.Body) -} - -func writeFrame(w io.Writer, typ uint8, channel uint16, payload []byte) (err error) { - end := []byte{frameEnd} - size := uint(len(payload)) - - _, err = w.Write([]byte{ - byte(typ), - byte((channel & 0xff00) >> 8), - byte((channel & 0x00ff) >> 0), - byte((size & 0xff000000) >> 24), - byte((size & 0x00ff0000) >> 16), - byte((size & 0x0000ff00) >> 8), - byte((size & 0x000000ff) >> 0), - }) - - if err != nil { - return - } - - if _, err = w.Write(payload); err != nil { - return - } - - if _, err = w.Write(end); err != nil { - return - } - - return -} - -func writeShortstr(w io.Writer, s string) (err error) { - b := []byte(s) - - var length uint8 = uint8(len(b)) - - if err = binary.Write(w, binary.BigEndian, length); err != nil { - return - } - - if _, err = w.Write(b[:length]); err != nil { - return - } - - return -} - -func writeLongstr(w io.Writer, s string) (err error) { - b := []byte(s) - - var length uint32 = uint32(len(b)) - - if err = binary.Write(w, binary.BigEndian, length); err != nil { - return - } - - if _, err = w.Write(b[:length]); err != nil { - return - } - - return -} - -/* -'A': []interface{} -'D': Decimal -'F': Table -'I': int32 -'S': string -'T': time.Time -'V': nil -'b': byte -'d': float64 -'f': float32 -'l': int64 -'s': int16 -'t': bool -'x': []byte -*/ -func writeField(w io.Writer, value interface{}) (err error) { - var buf [9]byte - var enc []byte - - switch v := value.(type) { - case bool: - buf[0] = 't' - if v { - buf[1] = byte(1) - } else { - buf[1] = byte(0) - } - enc = buf[:2] - - case byte: - buf[0] = 'b' - buf[1] = byte(v) - enc = buf[:2] - - case int16: - buf[0] = 's' - binary.BigEndian.PutUint16(buf[1:3], uint16(v)) - enc = buf[:3] - - case int32: - buf[0] = 'I' - binary.BigEndian.PutUint32(buf[1:5], uint32(v)) - enc = buf[:5] - - case int64: - buf[0] = 'l' - binary.BigEndian.PutUint64(buf[1:9], uint64(v)) - enc = buf[:9] - - case float32: - buf[0] = 'f' - binary.BigEndian.PutUint32(buf[1:5], math.Float32bits(v)) - enc = buf[:5] - - case float64: - buf[0] = 'd' - binary.BigEndian.PutUint64(buf[1:9], math.Float64bits(v)) - enc = buf[:9] - - case Decimal: - buf[0] = 'D' - buf[1] = byte(v.Scale) - binary.BigEndian.PutUint32(buf[2:6], uint32(v.Value)) - enc = buf[:6] - - case string: - buf[0] = 'S' - binary.BigEndian.PutUint32(buf[1:5], uint32(len(v))) - enc = append(buf[:5], []byte(v)...) - - case []interface{}: // field-array - buf[0] = 'A' - - sec := new(bytes.Buffer) - for _, val := range v { - if err = writeField(sec, val); err != nil { - return - } - } - - binary.BigEndian.PutUint32(buf[1:5], uint32(sec.Len())) - if _, err = w.Write(buf[:5]); err != nil { - return - } - - if _, err = w.Write(sec.Bytes()); err != nil { - return - } - - return - - case time.Time: - buf[0] = 'T' - binary.BigEndian.PutUint64(buf[1:9], uint64(v.Unix())) - enc = buf[:9] - - case Table: - if _, err = w.Write([]byte{'F'}); err != nil { - return - } - return writeTable(w, v) - - case []byte: - buf[0] = 'x' - binary.BigEndian.PutUint32(buf[1:5], uint32(len(v))) - if _, err = w.Write(buf[0:5]); err != nil { - return - } - if _, err = w.Write(v); err != nil { - return - } - return - - case nil: - buf[0] = 'V' - enc = buf[:1] - - default: - return ErrFieldType - } - - _, err = w.Write(enc) - - return -} - -func writeTable(w io.Writer, table Table) (err error) { - var buf bytes.Buffer - - for key, val := range table { - if err = writeShortstr(&buf, key); err != nil { - return - } - if err = writeField(&buf, val); err != nil { - return - } - } - - return writeLongstr(w, string(buf.Bytes())) -} From 834446260ffd5f3d1a00f6becbc23eee769d6f04 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 24 Oct 2017 14:19:53 +0200 Subject: [PATCH 11/39] changelog: adds note about closing #9645 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81ec87a58f4..f59f810d013 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ ## New Features * **Data Source Proxy**: Add support for whitelisting specified cookies that will be passed through to the data source when proxying data source requests [#5457](https://github.com/grafana/grafana/issues/5457), thanks [@robingustafsson](https://github.com/robingustafsson) + +## Tech +* **RabbitMq**: Remove support for publishing events to RabbitMQ [#9645](https://github.com/grafana/grafana/issues/9645) + ## Fixes * **Sensu**: Send alert message to sensu output [#9551](https://github.com/grafana/grafana/issues/9551), thx [@cjchand](https://github.com/cjchand) * **Singlestat**: suppress error when result contains no datapoints [#9636](https://github.com/grafana/grafana/issues/9636), thx [@utkarshcmu](https://github.com/utkarshcmu) From d99f4f95c0f9a9e4bbdf411a4b1f360d4fdf94f0 Mon Sep 17 00:00:00 2001 From: Alin Sinpalean Date: Tue, 24 Oct 2017 14:39:10 +0200 Subject: [PATCH 12/39] Allow for multiple auto interval template variables (#9216) * Allow for multiple auto interval template variables without them overwriting each other's value. * Add test for multiple auto interval template variables. * Correctly handle old links with . --- .../features/templating/interval_variable.ts | 5 +- .../templating/specs/template_srv.jest.ts | 4 +- .../templating/specs/variable_srv_specs.ts | 76 ++++++++++++++++++- 3 files changed, 80 insertions(+), 5 deletions(-) diff --git a/public/app/features/templating/interval_variable.ts b/public/app/features/templating/interval_variable.ts index 79c1860d0cf..5435a8054ec 100644 --- a/public/app/features/templating/interval_variable.ts +++ b/public/app/features/templating/interval_variable.ts @@ -5,6 +5,7 @@ import kbn from 'app/core/utils/kbn'; import {Variable, assignModelProperties, variableTypes} from './variable'; export class IntervalVariable implements Variable { + name: string; auto_count: number; auto_min: number; options: any; @@ -50,10 +51,12 @@ export class IntervalVariable implements Variable { // add auto option if missing if (this.options.length && this.options[0].text !== 'auto') { - this.options.unshift({ text: 'auto', value: '$__auto_interval' }); + this.options.unshift({ text: 'auto', value: '$__auto_interval_' + this.name }); } var res = kbn.calculateInterval(this.timeSrv.timeRange(), this.auto_count, this.auto_min); + this.templateSrv.setGrafanaVariable('$__auto_interval_' + this.name, res.interval); + // for backward compatibility, to be removed eventually this.templateSrv.setGrafanaVariable('$__auto_interval', res.interval); } diff --git a/public/app/features/templating/specs/template_srv.jest.ts b/public/app/features/templating/specs/template_srv.jest.ts index 178abc578b6..ae16811142f 100644 --- a/public/app/features/templating/specs/template_srv.jest.ts +++ b/public/app/features/templating/specs/template_srv.jest.ts @@ -254,9 +254,9 @@ describe('templateSrv', function() { beforeEach(function() { initTemplateSrv([ {type: 'query', name: 'server', current: { value: '{asd,asd2}', text: 'All' } }, - {type: 'interval', name: 'period', current: { value: '$__auto_interval', text: 'auto' } } + {type: 'interval', name: 'period', current: { value: '$__auto_interval_interval', text: 'auto' } } ]); - _templateSrv.setGrafanaVariable('$__auto_interval', '13m'); + _templateSrv.setGrafanaVariable('$__auto_interval_interval', '13m'); _templateSrv.updateTemplateData(); }); diff --git a/public/app/features/templating/specs/variable_srv_specs.ts b/public/app/features/templating/specs/variable_srv_specs.ts index 9afb38056bd..582ee48b331 100644 --- a/public/app/features/templating/specs/variable_srv_specs.ts +++ b/public/app/features/templating/specs/variable_srv_specs.ts @@ -84,11 +84,19 @@ describe('VariableSrv', function() { it('should update options array', function() { expect(scenario.variable.options.length).to.be(5); expect(scenario.variable.options[0].text).to.be('auto'); - expect(scenario.variable.options[0].value).to.be('$__auto_interval'); + expect(scenario.variable.options[0].value).to.be('$__auto_interval_test'); }); + it('should set $__auto_interval_test', function() { + var call = ctx.templateSrv.setGrafanaVariable.firstCall; + expect(call.args[0]).to.be('$__auto_interval_test'); + expect(call.args[1]).to.be('12h'); + }); + + // updateAutoValue() gets called twice: once directly once via VariableSrv.validateVariableSelectionState() + // So use lastCall instead of a specific call number it('should set $__auto_interval', function() { - var call = ctx.templateSrv.setGrafanaVariable.getCall(0); + var call = ctx.templateSrv.setGrafanaVariable.lastCall; expect(call.args[0]).to.be('$__auto_interval'); expect(call.args[1]).to.be('12h'); }); @@ -395,4 +403,68 @@ describe('VariableSrv', function() { expect(scenario.variable.options[1].value).to.be('hop'); }); }); + + describe('multiple interval variables with auto', function() { + var variable1, variable2; + + beforeEach(function() { + var range = { + from: moment(new Date()).subtract(7, 'days').toDate(), + to: new Date() + }; + ctx.timeSrv.timeRange = sinon.stub().returns(range); + ctx.templateSrv.setGrafanaVariable = sinon.spy(); + + var variableModel1 = {type: 'interval', query: '1s,2h,5h,1d', name: 'variable1', auto: true, auto_count: 10 }; + variable1 = ctx.variableSrv.createVariableFromModel(variableModel1); + ctx.variableSrv.addVariable(variable1); + + var variableModel2 = {type: 'interval', query: '1s,2h,5h', name: 'variable2', auto: true, auto_count: 1000 }; + variable2 = ctx.variableSrv.createVariableFromModel(variableModel2); + ctx.variableSrv.addVariable(variable2); + + ctx.variableSrv.updateOptions(variable1); + ctx.variableSrv.updateOptions(variable2); + ctx.$rootScope.$digest(); + }); + + it('should update options array', function() { + expect(variable1.options.length).to.be(5); + expect(variable1.options[0].text).to.be('auto'); + expect(variable1.options[0].value).to.be('$__auto_interval_variable1'); + expect(variable2.options.length).to.be(4); + expect(variable2.options[0].text).to.be('auto'); + expect(variable2.options[0].value).to.be('$__auto_interval_variable2'); + }); + + it('should correctly set $__auto_interval_variableX', function() { + var variable1Set, variable2Set, legacySet, unknownSet = false; + // updateAutoValue() gets called repeatedly: once directly once via VariableSrv.validateVariableSelectionState() + // So check that all calls are valid rather than expect a specific number and/or ordering of calls + for (var i = 0; i < ctx.templateSrv.setGrafanaVariable.callCount; i++) { + var call = ctx.templateSrv.setGrafanaVariable.getCall(i); + switch (call.args[0]) { + case '$__auto_interval_variable1': + expect(call.args[1]).to.be('12h'); + variable1Set = true; + break; + case '$__auto_interval_variable2': + expect(call.args[1]).to.be('10m'); + variable2Set = true; + break; + case '$__auto_interval': + expect(call.args[1]).to.match(/^(12h|10m)$/); + legacySet = true; + break; + default: + unknownSet = true; + break; + } + } + expect(variable1Set).to.be.equal(true); + expect(variable2Set).to.be.equal(true); + expect(legacySet).to.be.equal(true); + expect(unknownSet).to.be.equal(false); + }); + }); }); From 201e93b7f9ecfb6784a72087567ceeb69a663f29 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 24 Oct 2017 14:41:17 +0200 Subject: [PATCH 13/39] changelog: spelling --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f59f810d013..ff30ec53880 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ ## Fixes * **Sensu**: Send alert message to sensu output [#9551](https://github.com/grafana/grafana/issues/9551), thx [@cjchand](https://github.com/cjchand) * **Singlestat**: suppress error when result contains no datapoints [#9636](https://github.com/grafana/grafana/issues/9636), thx [@utkarshcmu](https://github.com/utkarshcmu) -* **Postgres/MySQL**: Control quoting in SQL-queries when using template variables [9030](https://github.com/grafana/grafana/issues/9030), thanks [@svenklemm](https://github.com/svenklemm) +* **Postgres/MySQL**: Control quoting in SQL-queries when using template variables [#9030](https://github.com/grafana/grafana/issues/9030), thanks [@svenklemm](https://github.com/svenklemm) # 4.6.0-beta4 (unreleased) From f48703502d9b159531cca90ba9c742940ed9e1a5 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 24 Oct 2017 14:42:13 +0200 Subject: [PATCH 14/39] docs: update for template variables ref #9030 --- docs/sources/features/datasources/mysql.md | 6 +++++- docs/sources/features/datasources/postgres.md | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/sources/features/datasources/mysql.md b/docs/sources/features/datasources/mysql.md index f277f45f3c8..f67ab5f3f13 100644 --- a/docs/sources/features/datasources/mysql.md +++ b/docs/sources/features/datasources/mysql.md @@ -142,7 +142,11 @@ SELECT hostname FROM my_host WHERE region IN($region) ### Using Variables in Queries -Template variables are quoted automatically so if it is a string value do not wrap them in quotes in where clauses. If the variable is a multi-value variable then use the `IN` comparison operator rather than `=` to match against multiple values. +From Grafana 4.3.0 to 4.6.0, template variables are always quoted automatically so if it is a string value do not wrap them in quotes in where clauses. + +From Grafana 4.7.0, template variable values are only quoted when the template variable is a `multi-value`. + +If the variable is a multi-value variable then use the `IN` comparison operator rather than `=` to match against multiple values. There are two syntaxes: diff --git a/docs/sources/features/datasources/postgres.md b/docs/sources/features/datasources/postgres.md index a4ef8277cd1..d9239b923ba 100644 --- a/docs/sources/features/datasources/postgres.md +++ b/docs/sources/features/datasources/postgres.md @@ -154,7 +154,11 @@ SELECT hostname FROM host WHERE region IN($region) ### Using Variables in Queries -Template variables are quoted automatically so if it is a string value do not wrap them in quotes in where clauses. If the variable is a multi-value variable then use the `IN` comparison operator rather than `=` to match against multiple values. +From Grafana 4.3.0 to 4.6.0, template variables are always quoted automatically so if it is a string value do not wrap them in quotes in where clauses. + +From Grafana 4.7.0, template variable values are only quoted when the template variable is a `multi-value`. + +If the variable is a multi-value variable then use the `IN` comparison operator rather than `=` to match against multiple values. There are two syntaxes: From fc76530577a461eed94f875312388b15e14eedb4 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 24 Oct 2017 15:13:04 +0200 Subject: [PATCH 15/39] docs: document annotations for postgres/mysql --- docs/sources/features/datasources/index.md | 3 ++- docs/sources/features/datasources/influxdb.md | 4 +-- docs/sources/features/datasources/mysql.md | 25 +++++++++++++++++-- docs/sources/features/datasources/postgres.md | 23 +++++++++++++++++ docs/sources/reference/annotations.md | 4 +-- 5 files changed, 51 insertions(+), 8 deletions(-) diff --git a/docs/sources/features/datasources/index.md b/docs/sources/features/datasources/index.md index 56501980c31..54606d20988 100644 --- a/docs/sources/features/datasources/index.md +++ b/docs/sources/features/datasources/index.md @@ -28,8 +28,9 @@ The following datasources are officially supported: * [InfluxDB]({{< relref "influxdb.md" >}}) * [OpenTSDB]({{< relref "opentsdb.md" >}}) * [Prometheus]({{< relref "prometheus.md" >}}) +* [MySQL]({{< relref "mysql.md" >}}) +* [Postgres]({{< relref "postgres.md" >}}) ## Data source plugins Since grafana 3.0 you can install data sources as plugins. Checkout [Grafana.net](https://grafana.com/plugins) for more data sources. - diff --git a/docs/sources/features/datasources/influxdb.md b/docs/sources/features/datasources/influxdb.md index 97e523cd151..6d0918a0d01 100644 --- a/docs/sources/features/datasources/influxdb.md +++ b/docs/sources/features/datasources/influxdb.md @@ -173,6 +173,4 @@ SELECT title, description from events WHERE $timeFilter order asc For InfluxDB you need to enter a query like in the above example. You need to have the ```where $timeFilter``` part. If you only select one column you will not need to enter anything in the column mapping fields. The -Tags field can be a comma seperated string. - - +Tags field can be a comma separated string. diff --git a/docs/sources/features/datasources/mysql.md b/docs/sources/features/datasources/mysql.md index f67ab5f3f13..69c6f667062 100644 --- a/docs/sources/features/datasources/mysql.md +++ b/docs/sources/features/datasources/mysql.md @@ -174,7 +174,28 @@ WHERE $__timeFilter(atimestamp) and hostname in([[hostname]]) ORDER BY atimestamp ASC ``` +## Annotations + +[Annotations]({{< relref "reference/annotations.md" >}}) allows you to overlay rich event information on top of graphs. You add annotation queries via the Dashboard menu / Annotations view. + +An example query: + +```sql +SELECT + UNIX_TIMESTAMP(atimestamp) as time_sec, + value as text, + CONCAT(tag1, ',', tag2) as tags +FROM my_table +WHERE $__timeFilter(atimestamp) +ORDER BY atimestamp ASC +``` + +Name | Description +------------ | ------------- +time_sec | The name of the date/time field. +text | Event description field. +tags | Optional field name to use for event tags as a comma separated string. + ## Alerting -Time series queries should work in alerting conditions. Table formatted queries is not yet supported in alert rule -conditions. +Time series queries should work in alerting conditions. Table formatted queries is not yet supported in alert rule conditions. diff --git a/docs/sources/features/datasources/postgres.md b/docs/sources/features/datasources/postgres.md index d9239b923ba..154f822d9d0 100644 --- a/docs/sources/features/datasources/postgres.md +++ b/docs/sources/features/datasources/postgres.md @@ -184,6 +184,29 @@ WHERE $__timeFilter(atimestamp) and hostname in([[hostname]]) ORDER BY atimestamp ASC ``` +## Annotations + +[Annotations]({{< relref "reference/annotations.md" >}}) allows you to overlay rich event information on top of graphs. You add annotation queries via the Dashboard menu / Annotations view. + +An example query: + +```sql +SELECT + extract(epoch from time_date_time) AS time, + metric1 as text, + concat_ws(', ', metric1::text, metric2::text) as tags +FROM + public.test_data +WHERE + $__timeFilter(time_date_time) +``` + +Name | Description +------------ | ------------- +time | The name of the date/time field. +text | Event description field. +tags | Optional field name to use for event tags as a comma separated string. + ## Alerting Time series queries should work in alerting conditions. Table formatted queries is not yet supported in alert rule diff --git a/docs/sources/reference/annotations.md b/docs/sources/reference/annotations.md index 3852c2c727b..de118f37d46 100644 --- a/docs/sources/reference/annotations.md +++ b/docs/sources/reference/annotations.md @@ -69,5 +69,5 @@ The annotation query options are different for each data source. - [Elasticsearch annotation queries]({{< relref "features/datasources/elasticsearch.md#annotations" >}}) - [InfluxDB annotation queries]({{< relref "features/datasources/influxdb.md#annotations" >}}) - [Prometheus annotation queries]({{< relref "features/datasources/prometheus.md#annotations" >}}) - - +- [MySQL annotation queries]({{< relref "features/datasources/mysql.md#annotations" >}}) +- [Postgres annotation queries]({{< relref "features/datasources/postgres.md#annotations" >}}) From 676a113966a5d721d8629b717d58e6a094292d00 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 24 Oct 2017 15:23:19 +0200 Subject: [PATCH 16/39] docs: update first page with data source guides --- docs/sources/index.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index f22ee82cc5c..9226c842abc 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -35,17 +35,19 @@ The back-end web server has a number of configuration options. Go the those options. -## Getting started +## Getting Started - [Getting Started]({{< relref "guides/getting_started.md" >}}) - [Basic Concepts]({{< relref "guides/basic_concepts.md" >}}) - [Screencasts]({{< relref "tutorials/screencasts.md" >}}) -## Data sources guides +## Data Source Guides - [Graphite]({{< relref "features/datasources/graphite.md" >}}) - [Elasticsearch]({{< relref "features/datasources/elasticsearch.md" >}}) - [InfluxDB]({{< relref "features/datasources/influxdb.md" >}}) -- [OpenTSDB]({{< relref "features/datasources/opentsdb.md" >}}) - - +- [Prometheus]({{< relref "features/datasources/influxdb.md" >}}) +- [OpenTSDB]({{< relref "features/datasources/prometheus.md" >}}) +- [MySQL]({{< relref "features/datasources/mysql.md" >}}) +- [Postgres]({{< relref "features/datasources/postgres.md" >}}) +- [Cloudwatch]({{< relref "features/datasources/cloudwatch.md" >}}) From 95250e4ea33cb0d2d23406e925fa3602c1db95e2 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Tue, 24 Oct 2017 16:13:49 +0200 Subject: [PATCH 17/39] replace store.js with store.ts, test for store.ts (#9646) --- .../layout_selector/layout_selector.ts | 2 - public/app/core/specs/store.jest.ts | 44 +++++++++++++++++++ public/app/core/store.js | 26 ----------- public/app/core/store.ts | 29 ++++++++++++ .../features/dashboard/impression_store.ts | 2 - 5 files changed, 73 insertions(+), 30 deletions(-) create mode 100644 public/app/core/specs/store.jest.ts delete mode 100644 public/app/core/store.js create mode 100644 public/app/core/store.ts diff --git a/public/app/core/components/layout_selector/layout_selector.ts b/public/app/core/components/layout_selector/layout_selector.ts index b2071723677..98f806cd63e 100644 --- a/public/app/core/components/layout_selector/layout_selector.ts +++ b/public/app/core/components/layout_selector/layout_selector.ts @@ -1,5 +1,3 @@ -/// - import store from 'app/core/store'; import coreModule from 'app/core/core_module'; diff --git a/public/app/core/specs/store.jest.ts b/public/app/core/specs/store.jest.ts new file mode 100644 index 00000000000..44cb2a84959 --- /dev/null +++ b/public/app/core/specs/store.jest.ts @@ -0,0 +1,44 @@ +import store from '../store'; + +Object.assign(window, { + localStorage: { + removeItem(key) { + delete window.localStorage[key]; + } + } +}); + +describe('store', () => { + + it("should store", ()=> { + store.set("key1", "123"); + expect(store.get("key1")).toBe("123"); + }); + + it("get key when undefined", ()=> { + expect(store.get("key2")).toBe(undefined); + }); + + it("check if key exixts", ()=> { + store.set("key3", "123"); + expect(store.exists("key3")).toBe(true); + }); + + it("get boolean when no key", ()=> { + expect(store.getBool("key4", false)).toBe(false); + }); + + it("get boolean", ()=> { + store.set("key5", "true"); + expect(store.getBool("key5", false)).toBe(true); + }); + + it("key should be deleted", ()=> { + store.set("key6", "123"); + store.delete("key6"); + expect(store.exists("key6")).toBe(false); + }); + +}); + + diff --git a/public/app/core/store.js b/public/app/core/store.js deleted file mode 100644 index 504b0e5aff5..00000000000 --- a/public/app/core/store.js +++ /dev/null @@ -1,26 +0,0 @@ -define([], function() { - 'use strict'; - - return { - get: function(key) { - return window.localStorage[key]; - }, - set: function(key, value) { - window.localStorage[key] = value; - }, - getBool: function(key, def) { - if (def !== void 0 && !this.exists(key)) { - return def; - } - return window.localStorage[key] === 'true'; - }, - exists: function(key) { - return window.localStorage[key] !== void 0; - }, - delete: function(key) { - window.localStorage.removeItem(key); - } - - }; - -}); diff --git a/public/app/core/store.ts b/public/app/core/store.ts new file mode 100644 index 00000000000..cbed16510ab --- /dev/null +++ b/public/app/core/store.ts @@ -0,0 +1,29 @@ +export class Store { + + get(key) { + return window.localStorage[key]; + } + + set(key, value) { + window.localStorage[key] = value; + } + + getBool(key, def) { + if (def !== void 0 && !this.exists(key)) { + return def; + } + return window.localStorage[key] === 'true'; + } + + exists(key) { + return window.localStorage[key] !== void 0; + } + + delete(key) { + window.localStorage.removeItem(key); + } + +} + +const store = new Store(); +export default store; diff --git a/public/app/features/dashboard/impression_store.ts b/public/app/features/dashboard/impression_store.ts index a0f20f7ec75..68478aef09a 100644 --- a/public/app/features/dashboard/impression_store.ts +++ b/public/app/features/dashboard/impression_store.ts @@ -1,5 +1,3 @@ -/// - import store from 'app/core/store'; import _ from 'lodash'; import config from 'app/core/config'; From 577478baff78fcbfec16f8a5ff368c89805aefe5 Mon Sep 17 00:00:00 2001 From: Jason O'Donnell Date: Tue, 24 Oct 2017 10:48:49 -0400 Subject: [PATCH 18/39] Fix typo in template help tab --- public/app/features/templating/partials/editor.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/templating/partials/editor.html b/public/app/features/templating/partials/editor.html index 5d110773cc7..5888af06a62 100644 --- a/public/app/features/templating/partials/editor.html +++ b/public/app/features/templating/partials/editor.html @@ -74,7 +74,7 @@
What does templating do?

Templating allows for more interactive and dynamic dashboards. Instead of hard-coding things like server, application - and sensor name in you metric queries you can use variables in their place. Variables are shown as dropdown select boxes at the top of + and sensor name in your metric queries you can use variables in their place. Variables are shown as dropdown select boxes at the top of the dashboard. These dropdowns make it easy to change the data being displayed in your dashboard.

From bddebf4c82c16f1f9d29a69e603ffd53f14a5a70 Mon Sep 17 00:00:00 2001 From: xjewer Date: Wed, 25 Oct 2017 09:14:14 +0300 Subject: [PATCH 19/39] add a phantomjs execution status to log if errors happens, e.g. OOM killer kills it (#9644) fixes #9643 --- pkg/components/renderer/renderer.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/components/renderer/renderer.go b/pkg/components/renderer/renderer.go index db36054e76d..d5980231f0e 100644 --- a/pkg/components/renderer/renderer.go +++ b/pkg/components/renderer/renderer.go @@ -121,7 +121,9 @@ func RenderToPng(params *RenderOpts) (string, error) { done := make(chan error) go func() { - cmd.Wait() + if err := cmd.Wait(); err != nil { + rendererLog.Error("failed to render an image", "error", err) + } close(done) }() From 2848773ab41abbfbc92c42248c30dcd77246d6a2 Mon Sep 17 00:00:00 2001 From: zhengkai Date: Wed, 25 Oct 2017 01:15:51 -0500 Subject: [PATCH 20/39] #edit_grafana_organisation_apis_doc (#9651) --- docs/sources/http_api/org.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/sources/http_api/org.md b/docs/sources/http_api/org.md index 6542f00fd81..4c1dff904c8 100644 --- a/docs/sources/http_api/org.md +++ b/docs/sources/http_api/org.md @@ -14,12 +14,12 @@ parent = "http_api" ## Get current Organisation -`GET /api/org` +`GET /api/org/` **Example Request**: ```http -GET /api/org HTTP/1.1 +GET /api/org/ HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk @@ -49,6 +49,8 @@ Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk ``` +Note: The api will only work when you pass the admin name and password +to the request http url, like http://admin:admin@localhost:3000/api/orgs/1 **Example Response**: @@ -81,6 +83,8 @@ Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk ``` +Note: The api will only work when you pass the admin name and password +to the request http url, like http://admin:admin@localhost:3000/api/orgs/name/Main%20Org%2E **Example Response**: @@ -118,6 +122,9 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk "name":"New Org." } ``` +Note: The api will work in the following two ways +1) Need to set GF_USERS_ALLOW_ORG_CREATE=true +2) Set the config users.allow_org_create to true in ini file **Example Response**: @@ -279,6 +286,8 @@ Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk ``` +Note: The api will only work when you pass the admin name and password +to the request http url, like http://admin:admin@localhost:3000/api/orgs **Example Response**: @@ -334,6 +343,9 @@ Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk ``` +Note: The api will only work when you pass the admin name and password +to the request http url, like http://admin:admin@localhost:3000/api/orgs/1/users + **Example Response**: From da6430ac01376a4a8e0c3880a74ffda1d2998830 Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 25 Oct 2017 09:39:27 +0200 Subject: [PATCH 21/39] datasource as cfg: explain why cmd.version can be higher --- pkg/services/sqlstore/datasource.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/services/sqlstore/datasource.go b/pkg/services/sqlstore/datasource.go index 3b4bef61a1d..b4974aa1fdf 100644 --- a/pkg/services/sqlstore/datasource.go +++ b/pkg/services/sqlstore/datasource.go @@ -152,7 +152,11 @@ func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error { var updateSession *xorm.Session if cmd.Version != 0 { - updateSession = sess.Where("id=? and org_id=? and (version = ? or version < ?)", ds.Id, ds.OrgId, cmd.Version, cmd.Version) + // the reason we allow cmd.version > db.version is make it possible for people to force + // updates to datasources using the datasource.yaml file without knowing exactly what version + // a datasource have in the db. + updateSession = sess.Where("id=? and org_id=? and version < ?", ds.Id, ds.OrgId, ds.Version) + } else { updateSession = sess.Where("id=? and org_id=?", ds.Id, ds.OrgId) } From 17d95dc848c598fa58c85e8874299f7adaa440bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 25 Oct 2017 11:23:47 +0200 Subject: [PATCH 22/39] Create codecov.yml --- codecov.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000000..3d764c1a5b1 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,11 @@ +coverage: + precision: 2 + round: down + range: "50...100" + + status: + project: yes + patch: yes + changes: no + +comment: false From d68bfaa8be13d639f10b01bc8e9c89a7d77606e0 Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 25 Oct 2017 11:29:19 +0200 Subject: [PATCH 23/39] datasource as cfg: typo --- pkg/api/datasources.go | 2 +- pkg/models/datasource.go | 7 +++---- pkg/services/sqlstore/datasource.go | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index 7c509499981..747ef8f25e6 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -139,7 +139,7 @@ func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) Resp err = bus.Dispatch(&cmd) if err != nil { - if err == m.ErrDataSouceUpdatingOldVersion { + if err == m.ErrDataSourceUpdatingOldVersion { return ApiError(500, "Failed to update datasource. Reload new version and try again", err) } else { return ApiError(500, "Failed to update datasource", err) diff --git a/pkg/models/datasource.go b/pkg/models/datasource.go index f600da75a63..7fc8f935124 100644 --- a/pkg/models/datasource.go +++ b/pkg/models/datasource.go @@ -23,11 +23,10 @@ const ( DS_ACCESS_PROXY = "proxy" ) -// Typed errors var ( - ErrDataSourceNotFound = errors.New("Data source not found") - ErrDataSourceNameExists = errors.New("Data source with same name already exists") - ErrDataSouceUpdatingOldVersion = errors.New("Trying to update old version of datasouce") + ErrDataSourceNotFound = errors.New("Data source not found") + ErrDataSourceNameExists = errors.New("Data source with same name already exists") + ErrDataSourceUpdatingOldVersion = errors.New("Trying to update old version of datasource") ) type DsAccess string diff --git a/pkg/services/sqlstore/datasource.go b/pkg/services/sqlstore/datasource.go index b4974aa1fdf..7069990c476 100644 --- a/pkg/services/sqlstore/datasource.go +++ b/pkg/services/sqlstore/datasource.go @@ -167,7 +167,7 @@ func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error { } if affected == 0 { - return m.ErrDataSouceUpdatingOldVersion + return m.ErrDataSourceUpdatingOldVersion } err = updateIsDefaultFlag(ds, sess) From 4b5929d577b33edc73e3fd50d0408c9e2fb83b4d Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Wed, 25 Oct 2017 12:32:19 +0200 Subject: [PATCH 24/39] converted timer.js to timer.ts (#9656) --- public/app/core/services/timer.js | 33 ------------------------------- public/app/core/services/timer.ts | 32 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 33 deletions(-) delete mode 100644 public/app/core/services/timer.js create mode 100644 public/app/core/services/timer.ts diff --git a/public/app/core/services/timer.js b/public/app/core/services/timer.js deleted file mode 100644 index 67ad02367c0..00000000000 --- a/public/app/core/services/timer.js +++ /dev/null @@ -1,33 +0,0 @@ -define([ - 'angular', - 'lodash', - '../core_module', -], -function (angular, _, coreModule) { - 'use strict'; - - coreModule.default.service('timer', function($timeout) { - // This service really just tracks a list of $timeout promises to give us a - // method for cancelling them all when we need to - - var timers = []; - - this.register = function(promise) { - timers.push(promise); - return promise; - }; - - this.cancel = function(promise) { - timers = _.without(timers,promise); - $timeout.cancel(promise); - }; - - this.cancelAll = function() { - _.each(timers, function(t) { - $timeout.cancel(t); - }); - timers = []; - }; - }); - -}); diff --git a/public/app/core/services/timer.ts b/public/app/core/services/timer.ts new file mode 100644 index 00000000000..c7f7aeb961d --- /dev/null +++ b/public/app/core/services/timer.ts @@ -0,0 +1,32 @@ +import _ from 'lodash'; +import coreModule from 'app/core/core_module'; + +export class Timer { + timers = []; + + /** @ngInject */ + constructor(private $timeout) { + } + + register(promise) { + this.timers.push(promise); + return promise; + } + + cancel(promise) { + console.log(promise); + this.timers = _.without(this.timers, promise); + this.$timeout.cancel(promise); + } + + cancelAll() { + _.each(this.timers, function (t) { + this.$timeout.cancel(t); + }); + this.timers = []; + } +} + +coreModule.service('timer', Timer); +// This service really just tracks a list of $timeout promises to give us a +// method for cancelling them all when we need to From aa3fc9f45f1c8abffb75adc287b3a310cc952a93 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Wed, 25 Oct 2017 12:32:33 +0200 Subject: [PATCH 25/39] converted outline.js to outline.ts (#9658) --- public/app/core/utils/outline.js | 32 ------------------------------ public/app/core/utils/outline.ts | 34 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 32 deletions(-) delete mode 100644 public/app/core/utils/outline.js create mode 100644 public/app/core/utils/outline.ts diff --git a/public/app/core/utils/outline.js b/public/app/core/utils/outline.js deleted file mode 100644 index f968b3e51f9..00000000000 --- a/public/app/core/utils/outline.js +++ /dev/null @@ -1,32 +0,0 @@ -// outline.js -// based on http://www.paciellogroup.com/blog/2012/04/how-to-remove-css-outlines-in-an-accessible-manner/ -(function(d) { - "use strict"; - - var style_element = d.createElement('STYLE'), - dom_events = 'addEventListener' in d, - add_event_listener = function(type, callback) { - // Basic cross-browser event handling - if(dom_events){ - d.addEventListener(type, callback); - } else { - d.attachEvent('on' + type, callback); - } - }, - set_css = function(css_text) { - // Handle setting of