kaspad/apiserver/mqtt/transactions.go
Ori Newman 532e57b61c [NOD-427] Add selected tip mqtt notification for the API server (#489)
* [NOD-427] Send notifications to `dag/selected-tip`

* [NOD-442] Add selected tip notification

* [NOD-427] Add comment to PublishSelectedTipNotification

* [NOD-427] Remove redundant argument from errors.Wrapf

* [NOD-427] Add handleBlockAddedMsg function

* [NOD-427] Return errors instead of panicking

* [NOD-427] Fix findHashOfBluestBlock to use []string instead of dbmodels.Block

* [NOD-427] Add constants

* [NOD-427] use path.Join instead of topic+address

* [NOD-427] Remove redundant select

* [NOD-427] Change break to return
2019-11-26 14:44:27 +02:00

95 lines
2.7 KiB
Go

package mqtt
import (
"github.com/daglabs/btcd/apiserver/apimodels"
"github.com/daglabs/btcd/apiserver/controllers"
"github.com/daglabs/btcd/apiserver/database"
"github.com/daglabs/btcd/btcjson"
"github.com/daglabs/btcd/rpcclient"
"github.com/jinzhu/gorm"
"path"
)
// PublishTransactionsNotifications publishes notification for each transaction of the given block
func PublishTransactionsNotifications(db *gorm.DB, rawTransactions []btcjson.TxRawResult) error {
if !isConnected() {
return nil
}
transactionIDs := make([]string, len(rawTransactions))
for i, tx := range rawTransactions {
transactionIDs[i] = tx.TxID
}
transactions, err := controllers.GetTransactionsByIDsHandler(db, transactionIDs)
if err != nil {
return err
}
for _, transaction := range transactions {
err = publishTransactionNotifications(transaction, "transactions")
if err != nil {
return err
}
}
return nil
}
func publishTransactionNotifications(transaction *apimodels.TransactionResponse, topic string) error {
addresses := uniqueAddressesForTransaction(transaction)
for _, address := range addresses {
err := publishTransactionNotificationForAddress(transaction, address, topic)
if err != nil {
return err
}
}
return nil
}
func uniqueAddressesForTransaction(transaction *apimodels.TransactionResponse) []string {
addressesMap := make(map[string]struct{})
addresses := []string{}
for _, output := range transaction.Outputs {
if _, exists := addressesMap[output.Address]; !exists {
addresses = append(addresses, output.Address)
addressesMap[output.Address] = struct{}{}
}
}
return addresses
}
func publishTransactionNotificationForAddress(transaction *apimodels.TransactionResponse, address string, topic string) error {
return publish(path.Join(topic, address), transaction)
}
// PublishAcceptedTransactionsNotifications publishes notification for each accepted transaction of the given chain-block
func PublishAcceptedTransactionsNotifications(addedChainBlocks []*rpcclient.ChainBlock) error {
db, err := database.DB()
if err != nil {
return err
}
for _, addedChainBlock := range addedChainBlocks {
for _, acceptedBlock := range addedChainBlock.AcceptedBlocks {
transactionIDs := make([]string, len(acceptedBlock.AcceptedTxIDs))
for i, acceptedTxID := range acceptedBlock.AcceptedTxIDs {
transactionIDs[i] = acceptedTxID.String()
}
transactions, err := controllers.GetTransactionsByIDsHandler(db, transactionIDs)
if err != nil {
return err
}
for _, transaction := range transactions {
err = publishTransactionNotifications(transaction, "transactions/accepted")
if err != nil {
return err
}
}
return nil
}
}
return nil
}