Пример #1
0
func fetchLatestMessage(msg *pandora.Message, db querier, inbox string, now time.Time, dur time.Duration) error {
	err := reEnqueueMessages(db, now)
	if err != nil {
		return err
	}
	inboxId, err := findInbox(db, inbox, false)
	if err != nil {
		return err
	}
	var buf []byte
	var id int64
	err = db.QueryRow(`select id, mid, status, receivedat, sendwhen, deliverycount
		from pgstore_messages
		where receiverid = $1
			and lid is null
			and sendwhen <= $2
			and status <> $3
		order by sendwhen asc
		limit 1`, inboxId, now, pandora.StatusConfirmed).Scan(&id, &buf, &msg.Status, &msg.ReceivedAt, &msg.SendWhen, &msg.DeliveryCount)
	if err == sql.ErrNoRows {
		return pandora.ErrNoMessages
	}
	if err != nil {
		return err
	}
	msg.Mid = &pandora.SHA1Key{}
	copy(msg.Mid.Bytes(), buf)
	msg.CalcualteLeaseFor(now, dur)

	_, err = db.Exec("update pgstore_messages set lid = $1, deliverycount = deliverycount + 1, leaseuntil = $2 where id = $3", msg.Lid.Bytes(), msg.LeasedUntil, id)
	return err
}
Пример #2
0
func findSenderReceiver(db querier, msg *pandora.Message, create bool) (sid int64, rid int64, err error) {
	senderName, receiverName := msg.Sender(), msg.Receiver()
	sid, err = findInbox(db, senderName, create)
	if err != nil {
		return
	}

	rid, err = findInbox(db, receiverName, create)
	if err != nil {
		return
	}
	return
}
Пример #3
0
// Enqueue will place the message inside the receiver inbox
func (ms *MessageStore) Enqueue(msg *pandora.Message) error {
	msg.Status = pandora.StatusNotDelivered
	msg.CalculateMid()
	return doInsideTransaction(ms.conn, func(tx querier) error {
		senderId, receiverId, err := findSenderReceiver(tx, msg, true)
		if err != nil {
			return err
		}
		var id int64
		err = tx.QueryRow("insert into pgstore_messages(mid, status, receivedat, sendwhen, deliverycount, senderid, receiverid) values ($1, $2, $3, $4, $5, $6, $7) returning id",
			msg.Mid.Bytes(), msg.Status, msg.ReceivedAt, msg.SendWhen, msg.DeliveryCount, senderId, receiverId).Scan(&id)
		return err
	})
}
Пример #4
0
func fetchHeaders(out []pandora.Message, db querier, inbox string, now, min time.Time) ([]pandora.Message, error) {
	err := reEnqueueMessages(db, now)
	if err != nil {
		return nil, err
	}

	inboxId, err := findInbox(db, inbox, false)
	if err != nil {
		return nil, err
	}
	results, err := db.Query(`select mid, status, receivedat, sendwhen, deliverycount
		from pgstore_messages
		where receiverid = $1
			and lid is null
			and sendwhen <= $2
			and receivedat > $3
			and status <> $4
		order by receivedat asc, sendwhen asc
		limit $5`, inboxId, now, min, pandora.StatusConfirmed, len(out))
	if err != nil {
		return nil, err
	}
	defer results.Close()
	var idx int
	var buf []byte
	for results.Next() {
		var msg *pandora.Message
		if idx < len(out) {
			msg = &out[idx]
		} else {
			break
		}
		msg.Mid = &pandora.SHA1Key{}
		err := results.Scan(&buf, &msg.Status, &msg.ReceivedAt, &msg.SendWhen, &msg.DeliveryCount)
		if err != nil {
			return out[:idx], err
		}
		copy(msg.Mid.Bytes(), buf)
		idx++
	}
	return out[:idx], err
}
Пример #5
0
// Send will update the given body with the paramters expected by a Pandora server
// and return the Mid generated by the server or an error.
func (mb *Mailbox) Send(from, to string, delay time.Duration, body url.Values) (string, error) {
	var msg pandora.Message
	msg.Empty(body)
	msg.SetSender(from)
	msg.SetReceiver(to)
	msg.SetClientTime(time.Now())
	msg.Set("delay", delay.String())

	res, err := mb.Client.PostForm(mb.BaseUrl+"/send", body)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()

	if res.StatusCode != http.StatusOK {
		return "", fmt.Errorf("invalid status code: %v", res.StatusCode)
	}

	buf, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}

	values, err := url.ParseQuery(string(buf))
	if err != nil {
		return "", err
	}

	if len(values.Get("error")) > 0 {
		return "", errors.New(values.Get("error"))
	}

	return values.Get("mid"), nil
}