From 664e179fba3a623091b461829a2cee956e9cbd03 Mon Sep 17 00:00:00 2001 From: Roland Osborne Date: Fri, 21 Jan 2022 13:18:35 -0800 Subject: [PATCH] adding notification support --- doc/api.oa3 | 1 - net/server/internal/api_addCard.go | 1 + net/server/internal/api_getOpenMessage.go | 2 +- net/server/internal/notify.go | 132 ++++++++++++++++++++++ net/server/internal/routers.go | 2 + net/server/internal/store/schema.go | 11 +- 6 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 net/server/internal/notify.go diff --git a/doc/api.oa3 b/doc/api.oa3 index b0ca7305..7c440a0e 100644 --- a/doc/api.oa3 +++ b/doc/api.oa3 @@ -3914,7 +3914,6 @@ components: required: - profile - content - - view # revision increment on sharing changes - group - label - card diff --git a/net/server/internal/api_addCard.go b/net/server/internal/api_addCard.go index b24f5714..891dae2c 100644 --- a/net/server/internal/api_addCard.go +++ b/net/server/internal/api_addCard.go @@ -49,6 +49,7 @@ func AddCard(w http.ResponseWriter, r *http.Request) { card.Node = identity.Node card.ProfileRevision = identity.Revision card.Status = APP_CARDCONFIRMED + card.ViewRevision = 0 } else { diff --git a/net/server/internal/api_getOpenMessage.go b/net/server/internal/api_getOpenMessage.go index f39204a9..f5ad2d11 100644 --- a/net/server/internal/api_getOpenMessage.go +++ b/net/server/internal/api_getOpenMessage.go @@ -36,7 +36,7 @@ func GetOpenMessage(w http.ResponseWriter, r *http.Request) { connect := &Connect{ Contact: card.Guid, Token: card.InToken, - ContentRevision: account.ViewRevision, + ContentRevision: account.ContentRevision + account.ViewRevision + card.ViewRevision, ProfileRevision: account.ProfileRevision, Handle: account.Username, Name: detail.Name, diff --git a/net/server/internal/notify.go b/net/server/internal/notify.go new file mode 100644 index 00000000..fc20a3b2 --- /dev/null +++ b/net/server/internal/notify.go @@ -0,0 +1,132 @@ +package databag + +import ( + "gorm.io/gorm" + "databag/internal/store" +) + +var notify = make(chan *store.Notification) +var notifyExit = make(chan bool, 1) + +func ExitNotifications() { + notifyExit <- true +} + +func SendNotifications() { + + // queue all saved notifications + var notifications []store.Notification + if err := store.DB.Find(¬ifications).Error; err != nil { + ErrMsg(err) + } + for _, notification := range notifications { + notify <- ¬ification + } + + // send notifications until exit + for { + select { + case notification := <-notify: + PrintMsg("SENDING") + PrintMsg(notification) + case <-notifyExit: + PrintMsg("EXITING") + } + } +} + +// notify all cards of profile change +func SetProfileNotification(account *store.Account) { + + // select all connected cards + var cards []store.Card + if err := store.DB.Where("account_id = ? AND status = ?", account.ID, APP_CARDCONNECTED).Find(&cards).Error; err != nil { + ErrMsg(err) + return + } + + // add new notification for each card + err := store.DB.Transaction(func(tx *gorm.DB) error { + for _, card := range cards { + notification := &store.Notification{ + Url: card.Node + "/contact/profile/revision", + Token: card.OutToken, + Revision: account.ProfileRevision, + } + if err := tx.Save(notification).Error; err != nil { + return err + } + notify <- notification + } + return nil + }) + if err != nil { + ErrMsg(err) + } +} + +// notify all cards of content change +// account.Content incremented by adding, updating, removing article +// account.View incremented by removing a group or label or adding or removing a group with label +func SetContentNotification(account *store.Account) { + + // select all connected cards + var cards []store.Card + if err := store.DB.Where("account_id = ? AND status = ?", account.ID, APP_CARDCONNECTED).Find(&cards).Error; err != nil { + ErrMsg(err) + return + } + + // add new notification for each card + err := store.DB.Transaction(func(tx *gorm.DB) error { + for _, card := range cards { + notification := &store.Notification{ + Url: card.Node + "/contact/content/revision", + Token: card.OutToken, + Revision: account.ViewRevision + account.ContentRevision + card.ViewRevision, + } + if err := tx.Save(notification).Error; err != nil { + return err + } + notify <- notification + } + return nil + }) + if err != nil { + ErrMsg(err) + } +} + +// notify single card of content change +// card.View incremented by adding or removing card from group or label +func SetContactContentNotification(account *store.Account, cardId string) { + + // select card if connected + var cards []store.Card + if err := store.DB.Where("account_id = ? AND status = ? AND card_id = ?", account.ID, APP_CARDCONNECTED, cardId).Find(&cards).Error; err != nil { + ErrMsg(err) + return + } + + // add new notification for card + err := store.DB.Transaction(func(tx *gorm.DB) error { + for _, card := range cards { + notification := &store.Notification{ + Url: card.Node + "/contact/content/revision", + Token: card.OutToken, + Revision: account.ViewRevision + account.ContentRevision + card.ViewRevision, + } + if err := tx.Save(notification).Error; err != nil { + return err + } + notify <- notification + } + return nil + }) + if err != nil { + ErrMsg(err) + } +} + + + diff --git a/net/server/internal/routers.go b/net/server/internal/routers.go index f45fc9ff..4787201a 100644 --- a/net/server/internal/routers.go +++ b/net/server/internal/routers.go @@ -28,6 +28,8 @@ type Routes []Route func NewRouter() *mux.Router { + go SendNotifications() + router := mux.NewRouter().StrictSlash(true) for _, route := range routes { var handler http.Handler diff --git a/net/server/internal/store/schema.go b/net/server/internal/store/schema.go index 85431b61..8e69ccc1 100644 --- a/net/server/internal/store/schema.go +++ b/net/server/internal/store/schema.go @@ -3,6 +3,7 @@ package store import "gorm.io/gorm" func AutoMigrate(db *gorm.DB) { + db.AutoMigrate(&Notification{}); db.AutoMigrate(&Config{}); db.AutoMigrate(&App{}); db.AutoMigrate(&Account{}); @@ -26,6 +27,13 @@ func AutoMigrate(db *gorm.DB) { db.AutoMigrate(&TopicTag{}); } +type Notification struct { + ID uint `gorm:"primaryKey;not null;unique;autoIncrement"` + Url string `gorm:"not null"` + Token string `gorm:"not null"` + Revision int64 `gorm:"not null"` +} + type Config struct { ID uint `gorm:"primaryKey;not null;unique;autoIncrement"` ConfigId string `gorm:"not null;uniqueIndex"` @@ -53,12 +61,12 @@ type Account struct { Password []byte `gorm:"not null"` ProfileRevision int64 `gorm:"not null;default:1"` ContentRevision int64 `gorm:"not null;default:1"` - ViewRevision int64 `gorm:"not null;default:1"` GroupRevision int64 `gorm:"not null;default:1"` LabelRevision int64 `gorm:"not null;default:1"` CardRevision int64 `gorm:"not null;default:1"` DialogueRevision int64 `gorm:"not null;default:1"` InsightRevision int64 `gorm:"not null;default:1"` + ViewRevision int64 `gorm:"not null;default:1"` Created int64 `gorm:"autoCreateTime"` Disabled bool `gorm:"not null;default:false"` AccountDetail AccountDetail @@ -132,6 +140,7 @@ type Card struct { DataRevision int64 `gorm:"not null"` Created int64 `gorm:"autoCreateTime"` Updated int64 `gorm:"autoUpdateTime"` + ViewRevision int64 `gorm:"not null"` RemoteProfile int64 RemoteContent int64 Account Account