Пример #1
0
func (rc RequestChan) publish() error {
	var (
		err error
		out *amqp.Channel
	)
	for r := range rc {
		if r == nil {
			break
		}
		for out == nil {
			out, err = dial()
			if err != nil {
				out = nil
				log.Println(err)
				time.Sleep(*backoff)
			}
		}

		err = out.Publish(*exchange, *key, false, false,
			amqp.Publishing{
				Headers:     amqp.Table(r.Headers),
				ContentType: r.ContentType,
				Body:        r.Body,
			},
		)
		if err != nil {
			return err
		}
	}
	return nil
}
Пример #2
0
func (rc requestCh) publish() error {
	var (
		err error
		out *amqp.Channel
	)
	for r := range rc {
		if r == nil {
			break
		}
		for out == nil {
			out, err = dial()
			if err != nil {
				out = nil
				log.Println(err)
				time.Sleep(*backoff)
			}
		}

		err = out.Publish(*exchange, *key, false, false,
			amqp.Publishing{
				Headers:      amqp.Table(r.headers),
				DeliveryMode: amqp.Persistent,
				Body:         []byte(r.body),
			},
		)
		if err != nil {
			return err
		}
	}
	return nil
}
Пример #3
0
func NewRequestFromProto(req proto.Message) *Request {
	protoBytes := make([]byte, 0)
	if req != nil {
		protoBytes, _ = proto.Marshal(req)
	}

	result := NewRequestFromDelivery(amqp.Delivery{
		Body:        protoBytes,
		ContentType: "application/octetstream",
		Headers:     amqp.Table(make(map[string]interface{})),
	})
	result.unmarshaledData = req
	return result
}
Пример #4
0
// Publish places a new message on the default queue
func (amqpBroker *AMQPBroker) Publish(signature *signatures.TaskSignature) error {
	conn, channel, _, confirmsChan, err := amqpBroker.open()
	if err != nil {
		return err
	}

	defer amqpBroker.close(channel, conn)

	message, err := json.Marshal(signature)
	if err != nil {
		return fmt.Errorf("JSON Encode Message: %v", err)
	}

	signature.AdjustRoutingKey(
		amqpBroker.config.ExchangeType,
		amqpBroker.config.BindingKey,
		amqpBroker.config.DefaultQueue,
	)
	if err := channel.Publish(
		amqpBroker.config.Exchange, // exchange
		signature.RoutingKey,       // routing key
		false,                      // mandatory
		false,                      // immediate
		amqp.Publishing{
			Headers:      amqp.Table(signature.Headers),
			ContentType:  "application/json",
			Body:         message,
			DeliveryMode: amqp.Persistent,
		},
	); err != nil {
		return err
	}

	confirmed := <-confirmsChan

	if confirmed.Ack {
		return nil
	}

	return fmt.Errorf("Failed delivery of delivery tag: %v", confirmed.DeliveryTag)
}
Пример #5
0
// Connects to the message queue, opens a channel, declares a queue
func (amqpBroker *AMQPBroker) open() (*amqp.Connection, *amqp.Channel, amqp.Queue, <-chan amqp.Confirmation, error) {
	var (
		conn    *amqp.Connection
		channel *amqp.Channel
		queue   amqp.Queue
		err     error
	)

	// Connect
	// From amqp docs: 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.
	conn, err = amqp.DialTLS(amqpBroker.config.Broker, amqpBroker.config.TLSConfig)

	if err != nil {
		return conn, channel, queue, nil, fmt.Errorf("Dial: %s", err)
	}

	// Open a channel
	channel, err = conn.Channel()
	if err != nil {
		return conn, channel, queue, nil, fmt.Errorf("Channel: %s", err)
	}

	// Declare an exchange
	if err := channel.ExchangeDeclare(
		amqpBroker.config.Exchange,     // name of the exchange
		amqpBroker.config.ExchangeType, // type
		true,  // durable
		false, // delete when complete
		false, // internal
		false, // noWait
		nil,   // arguments
	); err != nil {
		return conn, channel, queue, nil, fmt.Errorf("Exchange Declare: %s", err)
	}

	// Declare a queue
	queue, err = channel.QueueDeclare(
		amqpBroker.config.DefaultQueue, // name
		true,  // durable
		false, // delete when unused
		false, // exclusive
		false, // no-wait
		nil,   // arguments
	)
	if err != nil {
		return conn, channel, queue, nil, fmt.Errorf("Queue Declare: %s", err)
	}

	// Bind the queue
	if err := channel.QueueBind(
		queue.Name,                   // name of the queue
		amqpBroker.config.BindingKey, // binding key
		amqpBroker.config.Exchange,   // source exchange
		false, // noWait
		amqp.Table(amqpBroker.config.QueueBindingArguments), // arguments
	); err != nil {
		return conn, channel, queue, nil, fmt.Errorf("Queue Bind: %s", err)
	}

	// Enable publish confirmations
	if err := channel.Confirm(false); err != nil {
		return conn, channel, queue, nil, fmt.Errorf("Channel could not be put into confirm mode: %s", err)
	}

	return conn, channel, queue, channel.NotifyPublish(make(chan amqp.Confirmation, 1)), nil
}
Пример #6
0
func main() {
	server := os.Getenv("AMQP_URL")
	if server == "" {
		server = os.ExpandEnv("amqp://$AMQP_USER:[email protected]:5672")
	}
	timeout := 5 * time.Second
	clientID, _ := os.Hostname()
	queue := "scanner"
	mainCmd := &cobra.Command{
		Use: "amqpc",
	}
	p := mainCmd.PersistentFlags()
	p.StringVarP(&server, "server", "S", server, "server address")
	p.DurationVarP(&timeout, "timeout", "", timeout, "timeout for commands")
	p.StringVarP(&clientID, "id", "", clientID, "client ID")
	p.StringVarP(&queue, "queue", "q", queue, "queue name to publish")

	appID := queue
	var noCompress bool
	pubCmd := &cobra.Command{
		Use:     "pub",
		Aliases: []string{"publish", "send", "write"},
		Run: func(_ *cobra.Command, args []string) {
			c, err := newClient(server, queue)
			if err != nil {
				log.Fatal(err)
			}
			defer c.Close()
			if err = c.Confirm(false); err != nil {
				log.Fatal(err)
			}
			confirms := c.NotifyPublish(make(chan amqp.Confirmation, 1))
			returns := c.NotifyReturn(make(chan amqp.Return, 1))

			var sendCount int
			tbl := make(map[string]interface{}, 1)
			for _, arg := range args {
				for k := range tbl {
					delete(tbl, k)
				}
				var r io.ReadCloser
				mimeType, contentEncoding := "text/plain", ""
				if strings.HasPrefix(arg, "@") {
					arg = arg[1:]
					if arg == "-" {
						r = os.Stdin
					} else if fh, err := os.Open(arg); err != nil {
						log.Fatal(err)
					} else {
						if noCompress {
							r = fh
						} else {
							pr, pw := io.Pipe()
							go func() {
								defer fh.Close()
								gw := gzip.NewWriter(pw)
								if _, err := io.Copy(gw, fh); err != nil {
									pw.CloseWithError(err)
									return
								}
								pw.CloseWithError(gw.Close())
							}()
							r = pr
							contentEncoding = "application/gzip"
						}
						tbl["FileName"] = arg
						if err := amqp.Table(tbl).Validate(); err != nil {
							log.Fatal(err)
						}
						mimeType = mime.TypeByExtension(filepath.Ext(arg))
					}
				} else {
					r = ioutil.NopCloser(strings.NewReader(arg))
				}
				b, err := ioutil.ReadAll(&io.LimitedReader{R: r, N: 256 << 20})
				r.Close()
				if err != nil {
					log.Fatal(err)
				}
				if mimeType == "" {
					if mimeType = magic.MIMEType(b); mimeType == "" {
						mimeType = "application/octet-stream"
					}
				}
				if err := c.Publish("", c.Queue.Name, false, false,
					amqp.Publishing{
						Headers:         tbl,
						DeliveryMode:    amqp.Persistent,
						ContentType:     mimeType,
						ContentEncoding: contentEncoding,
						AppId:           appID,
						Body:            b,
					},
				); err != nil {
					log.Fatalf("Publish: %v", err)
				}
				log.Printf("Sent %q", arg)
				sendCount++
			}

		Loop:
			for i := 0; i < sendCount; {
				select {
				case c, ok := <-confirms:
					if !ok {
						break Loop
					}
					if !c.Ack {
						log.Printf("couldn't deliver %d", c.DeliveryTag)
					} else {
						log.Printf("Delivered %d.", c.DeliveryTag)
						i++
					}
				case r, ok := <-returns:
					if !ok {
						break Loop
					}
					log.Printf("RETURN: %#v", r)
					i++
				}
			}
		},
	}
	f := pubCmd.Flags()
	f.StringVarP(&appID, "app-id", "", appID, "appID")
	f.BoolVarP(&noCompress, "no-compress", "", noCompress, "disable file data compression (for slow devices)")

	var keepFiles bool
	subCmd := &cobra.Command{
		Use:     "sub",
		Aliases: []string{"subscribe", "recv", "receive", "read"},
		Run: func(_ *cobra.Command, args []string) {
			c, err := newClient(server, queue)
			if err != nil {
				log.Fatal(err)
			}
			defer c.Close()

			d, err := c.Consume(c.Queue.Name, clientID, false, false, false, false, nil)
			if err != nil {
				log.Fatal(err)
			}
			tempDir, err := ioutil.TempDir("", "amqpc-")
			if err != nil {
				log.Fatal(err)
			}
			defer os.RemoveAll(tempDir)
			var i uint64
			for msg := range d {
				i++
				log.Printf("Received %s with %q from %s@%s.",
					msg.MessageId, msg.Headers, msg.UserId, msg.AppId)
				var fn string
				if fnI := msg.Headers["FileName"]; fnI != nil {
					if fn, _ = fnI.(string); fn != "" {
						fn = filepath.Base(fn)
					}
				}
				if fn == "" {
					var ext string
					if exts, err := mime.ExtensionsByType(msg.ContentType); err != nil {
						log.Printf("Extension for %q: %v", msg.ContentType)
					} else if len(ext) > 0 {
						ext = exts[0]
					}
					fn = fmt.Sprintf("%09d%s", i, ext)
				}
				fn = filepath.Join(tempDir, fn)

				err = receive(fn, msg, args)
				if !keepFiles {
					os.Remove(fn)
				}
				if err != nil {
					msg.Nack(false, true)
					log.Fatal(err)
				}
				if err := msg.Ack(false); err != nil {
					log.Printf("cannot ACK %q: %v", msg, err)
				}
			}
		},
	}
	subCmd.Flags().BoolVarP(&keepFiles, "keep-files", "x", keepFiles, "keep temporary files")

	mainCmd.AddCommand(pubCmd, subCmd)
	mainCmd.Execute()
}