From e0e249865e44e8f184d8bdbacd3bed1d6b88bb3b Mon Sep 17 00:00:00 2001 From: O F Date: Wed, 29 Nov 2023 16:39:43 -0800 Subject: [PATCH] feat(ds-host): add AppUrlDataEvents - add AppUrlDataEvents to events - create mock AppUrlDataEvents using Generic interfaces - appmodel sends AppUrlDataEvent when appropriate --- cmd/ds-host/ds-host.go | 4 +- cmd/ds-host/events/events.go | 24 +++++ cmd/ds-host/events/genericevents.go | 8 +- cmd/ds-host/models/appmodel/appmodel.go | 27 +++++- cmd/ds-host/testmocks/events.go | 22 ++++- cmd/ds-host/testmocks/events_mocks.go | 119 +++++++++++++++++++++++- 6 files changed, 192 insertions(+), 12 deletions(-) diff --git a/cmd/ds-host/ds-host.go b/cmd/ds-host/ds-host.go index 22732a4..7af67a7 100644 --- a/cmd/ds-host/ds-host.go +++ b/cmd/ds-host/ds-host.go @@ -155,6 +155,7 @@ func main() { appspaceFilesEvents := &events.AppspaceFilesEvents{} appspaceStatusEvents := &events.AppspaceStatusEvents{} migrationJobEvents := &events.MigrationJobEvents{} + appUrlDataEvents := &events.AppUrlDataEvents{} // models settingsModel := &settingsmodel.SettingsModel{ @@ -186,7 +187,8 @@ func main() { Config: runtimeConfig} appModel := &appmodel.AppModel{ - DB: db} + DB: db, + AppUrlDataEvents: appUrlDataEvents} appModel.PrepareStatements() appspaceFilesModel := &appspacefilesmodel.AppspaceFilesModel{ diff --git a/cmd/ds-host/events/events.go b/cmd/ds-host/events/events.go index d990516..a618dc6 100644 --- a/cmd/ds-host/events/events.go +++ b/cmd/ds-host/events/events.go @@ -210,3 +210,27 @@ func (e *AppspaceRouteHitEvents) removeSubscriber(ch chan<- *domain.AppspaceRout } } } + +// AppUrlDataEvents sends AppURLData +type AppUrlDataEvents struct { + ownerSubs eventIDSubs[domain.UserID, domain.AppURLData] + appSubs eventIDSubs[domain.AppID, domain.AppURLData] +} + +func (e *AppUrlDataEvents) SubscribeOwner(ownerID domain.UserID) <-chan domain.AppURLData { + return e.appSubs.subscribe(domain.AppID(ownerID)) +} + +func (e *AppUrlDataEvents) SubscribeApp(appID domain.AppID) <-chan domain.AppURLData { + return e.appSubs.subscribe(appID) +} + +func (e *AppUrlDataEvents) Unsubscribe(ch <-chan domain.AppURLData) { + e.appSubs.unsubscribe(ch) + e.ownerSubs.unsubscribe(ch) +} + +func (e *AppUrlDataEvents) Send(ownerID domain.UserID, data domain.AppURLData) { + e.ownerSubs.send(ownerID, data) + e.appSubs.send(data.AppID, data) +} diff --git a/cmd/ds-host/events/genericevents.go b/cmd/ds-host/events/genericevents.go index 1d3688c..4d77e89 100644 --- a/cmd/ds-host/events/genericevents.go +++ b/cmd/ds-host/events/genericevents.go @@ -6,14 +6,14 @@ import ( "github.com/teleclimber/DropServer/cmd/ds-host/domain" ) -type subIDs interface { +type SubscribeIDs interface { domain.UserID | domain.AppID | domain.AppspaceID } -type dataTypes interface { +type DataTypes interface { domain.AppURLData | domain.AppspaceID } -type eventIDSubs[T subIDs, D dataTypes] struct { +type eventIDSubs[T SubscribeIDs, D DataTypes] struct { subsMux sync.Mutex subscribers map[T]*eventSubs[D] } @@ -53,7 +53,7 @@ func (s *eventIDSubs[T, D]) send(subID T, data D) { } } -type eventSubs[D dataTypes] struct { +type eventSubs[D DataTypes] struct { subsMux sync.Mutex subscribers []chan D } diff --git a/cmd/ds-host/models/appmodel/appmodel.go b/cmd/ds-host/models/appmodel/appmodel.go index b1db666..7e733e0 100644 --- a/cmd/ds-host/models/appmodel/appmodel.go +++ b/cmd/ds-host/models/appmodel/appmodel.go @@ -22,7 +22,10 @@ type stmtPreparer interface { // AppModel represents the model for app type AppModel struct { DB *domain.DB - // need config to select db type? + + AppUrlDataEvents interface { + Send(ownerID domain.UserID, data domain.AppURLData) + } stmt struct { selectID *sqlx.Stmt @@ -221,6 +224,8 @@ func (m *AppModel) CreateFromURL(ownerID domain.UserID, url string, auto bool, l return domain.AppID(0), err } + m.sendAppURLDataEvent(appID) + return appID, nil } @@ -361,6 +366,7 @@ func (m *AppModel) UpdateAutomatic(appID domain.AppID, auto bool) error { m.getLogger("UpdateAutomatic(), Preparex()").AppID(appID).Error(err) return err } + m.sendAppURLDataEvent(appID) return nil } @@ -417,6 +423,7 @@ func (m *AppModel) SetLastFetch(appID domain.AppID, lastDt time.Time, lastResult m.getLogger("SetLastFetch(), setLast()").AppID(appID).Error(err) return err } + m.sendAppURLDataEvent(appID) return nil } @@ -451,6 +458,7 @@ func (m *AppModel) SetListing(appID domain.AppID, listingFetch domain.AppListing } tx.Commit() + m.sendAppURLDataEvent(appID) return nil } @@ -461,6 +469,7 @@ func (m *AppModel) SetNewUrl(appID domain.AppID, url string, dt nulltypes.NullTi m.getLogger("SetNewUrl(), setNewUrl()").AppID(appID).Error(err) return err } + m.sendAppURLDataEvent(appID) return nil } @@ -506,6 +515,7 @@ func (m *AppModel) UpdateURL(appID domain.AppID, url string, listingFetch domain } tx.Commit() + m.sendAppURLDataEvent(appID) return nil } @@ -556,6 +566,21 @@ func setListing(appID domain.AppID, l domain.AppListingFetch, sp stmtPreparer) e return err } +func (m *AppModel) sendAppURLDataEvent(appID domain.AppID) { + if m.AppUrlDataEvents == nil { + return + } + app, err := m.GetFromID(appID) + if err != nil { + return + } + urlData, err := m.GetAppUrlData(appID) + if err != nil { + return + } + m.AppUrlDataEvents.Send(app.OwnerID, urlData) +} + // GetVersion returns the version for the app func (m *AppModel) GetVersion(appID domain.AppID, version domain.Version) (domain.AppVersion, error) { var appVersion domain.AppVersion diff --git a/cmd/ds-host/testmocks/events.go b/cmd/ds-host/testmocks/events.go index 6a2f18e..055356f 100644 --- a/cmd/ds-host/testmocks/events.go +++ b/cmd/ds-host/testmocks/events.go @@ -2,18 +2,30 @@ package testmocks import ( "github.com/teleclimber/DropServer/cmd/ds-host/domain" + "github.com/teleclimber/DropServer/cmd/ds-host/events" ) -//go:generate mockgen -destination=events_mocks.go -package=testmocks github.com/teleclimber/DropServer/cmd/ds-host/testmocks AppspaceFilesEvents,AppspaceStatusEvents +//go:generate mockgen -destination=events_mocks.go -package=testmocks github.com/teleclimber/DropServer/cmd/ds-host/testmocks AppspaceFilesEvents,AppUrlDataEvents,AppspaceStatusEvents // xxx go:generate mockgen -source=$GOFILE // ^^ the above fails with an internal error: nil Pkg imports which I have no idea how to fix. -// AppspaceFilesEvents interface for mocking +type GenericEvents[D events.DataTypes] interface { + Subscribe() <-chan D + SubscribeOwner(domain.UserID) <-chan D + SubscribeApp(domain.AppID) <-chan D + // more subs... + Unsubscribe(ch <-chan D) +} + type AppspaceFilesEvents interface { - Send(appspaceID domain.AppspaceID) - Subscribe() <-chan domain.AppspaceID - Unsubscribe(ch <-chan domain.AppspaceID) + Send(domain.AppspaceID) + GenericEvents[domain.AppspaceID] +} + +type AppUrlDataEvents interface { + Send(domain.UserID, domain.AppURLData) + GenericEvents[domain.AppURLData] } // AppspaceStatusEvents interface for mocking diff --git a/cmd/ds-host/testmocks/events_mocks.go b/cmd/ds-host/testmocks/events_mocks.go index dabbeb1..3b7c959 100644 --- a/cmd/ds-host/testmocks/events_mocks.go +++ b/cmd/ds-host/testmocks/events_mocks.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/teleclimber/DropServer/cmd/ds-host/testmocks (interfaces: AppspaceFilesEvents,AppspaceStatusEvents) +// Source: github.com/teleclimber/DropServer/cmd/ds-host/testmocks (interfaces: AppspaceFilesEvents,AppUrlDataEvents,AppspaceStatusEvents) // Package testmocks is a generated GoMock package. package testmocks @@ -59,6 +59,34 @@ func (mr *MockAppspaceFilesEventsMockRecorder) Subscribe() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Subscribe", reflect.TypeOf((*MockAppspaceFilesEvents)(nil).Subscribe)) } +// SubscribeApp mocks base method +func (m *MockAppspaceFilesEvents) SubscribeApp(arg0 domain.AppID) <-chan domain.AppspaceID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribeApp", arg0) + ret0, _ := ret[0].(<-chan domain.AppspaceID) + return ret0 +} + +// SubscribeApp indicates an expected call of SubscribeApp +func (mr *MockAppspaceFilesEventsMockRecorder) SubscribeApp(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeApp", reflect.TypeOf((*MockAppspaceFilesEvents)(nil).SubscribeApp), arg0) +} + +// SubscribeOwner mocks base method +func (m *MockAppspaceFilesEvents) SubscribeOwner(arg0 domain.UserID) <-chan domain.AppspaceID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribeOwner", arg0) + ret0, _ := ret[0].(<-chan domain.AppspaceID) + return ret0 +} + +// SubscribeOwner indicates an expected call of SubscribeOwner +func (mr *MockAppspaceFilesEventsMockRecorder) SubscribeOwner(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeOwner", reflect.TypeOf((*MockAppspaceFilesEvents)(nil).SubscribeOwner), arg0) +} + // Unsubscribe mocks base method func (m *MockAppspaceFilesEvents) Unsubscribe(arg0 <-chan domain.AppspaceID) { m.ctrl.T.Helper() @@ -71,6 +99,95 @@ func (mr *MockAppspaceFilesEventsMockRecorder) Unsubscribe(arg0 interface{}) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unsubscribe", reflect.TypeOf((*MockAppspaceFilesEvents)(nil).Unsubscribe), arg0) } +// MockAppUrlDataEvents is a mock of AppUrlDataEvents interface +type MockAppUrlDataEvents struct { + ctrl *gomock.Controller + recorder *MockAppUrlDataEventsMockRecorder +} + +// MockAppUrlDataEventsMockRecorder is the mock recorder for MockAppUrlDataEvents +type MockAppUrlDataEventsMockRecorder struct { + mock *MockAppUrlDataEvents +} + +// NewMockAppUrlDataEvents creates a new mock instance +func NewMockAppUrlDataEvents(ctrl *gomock.Controller) *MockAppUrlDataEvents { + mock := &MockAppUrlDataEvents{ctrl: ctrl} + mock.recorder = &MockAppUrlDataEventsMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockAppUrlDataEvents) EXPECT() *MockAppUrlDataEventsMockRecorder { + return m.recorder +} + +// Send mocks base method +func (m *MockAppUrlDataEvents) Send(arg0 domain.UserID, arg1 domain.AppURLData) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Send", arg0, arg1) +} + +// Send indicates an expected call of Send +func (mr *MockAppUrlDataEventsMockRecorder) Send(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockAppUrlDataEvents)(nil).Send), arg0, arg1) +} + +// Subscribe mocks base method +func (m *MockAppUrlDataEvents) Subscribe() <-chan domain.AppURLData { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Subscribe") + ret0, _ := ret[0].(<-chan domain.AppURLData) + return ret0 +} + +// Subscribe indicates an expected call of Subscribe +func (mr *MockAppUrlDataEventsMockRecorder) Subscribe() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Subscribe", reflect.TypeOf((*MockAppUrlDataEvents)(nil).Subscribe)) +} + +// SubscribeApp mocks base method +func (m *MockAppUrlDataEvents) SubscribeApp(arg0 domain.AppID) <-chan domain.AppURLData { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribeApp", arg0) + ret0, _ := ret[0].(<-chan domain.AppURLData) + return ret0 +} + +// SubscribeApp indicates an expected call of SubscribeApp +func (mr *MockAppUrlDataEventsMockRecorder) SubscribeApp(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeApp", reflect.TypeOf((*MockAppUrlDataEvents)(nil).SubscribeApp), arg0) +} + +// SubscribeOwner mocks base method +func (m *MockAppUrlDataEvents) SubscribeOwner(arg0 domain.UserID) <-chan domain.AppURLData { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribeOwner", arg0) + ret0, _ := ret[0].(<-chan domain.AppURLData) + return ret0 +} + +// SubscribeOwner indicates an expected call of SubscribeOwner +func (mr *MockAppUrlDataEventsMockRecorder) SubscribeOwner(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeOwner", reflect.TypeOf((*MockAppUrlDataEvents)(nil).SubscribeOwner), arg0) +} + +// Unsubscribe mocks base method +func (m *MockAppUrlDataEvents) Unsubscribe(arg0 <-chan domain.AppURLData) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Unsubscribe", arg0) +} + +// Unsubscribe indicates an expected call of Unsubscribe +func (mr *MockAppUrlDataEventsMockRecorder) Unsubscribe(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unsubscribe", reflect.TypeOf((*MockAppUrlDataEvents)(nil).Unsubscribe), arg0) +} + // MockAppspaceStatusEvents is a mock of AppspaceStatusEvents interface type MockAppspaceStatusEvents struct { ctrl *gomock.Controller