Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
+203
View File
@@ -0,0 +1,203 @@
// Copyright 2018-2021 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package events
import (
"context"
"log"
"reflect"
"github.com/google/uuid"
ctxpkg "github.com/opencloud-eu/reva/v2/pkg/ctx"
"go-micro.dev/v4/events"
"go.opentelemetry.io/otel/propagation"
)
var (
// MainQueueName is the name of the main queue
// All events will go through here as they are forwarded to the consumer via the
// group name
// TODO: "fan-out" so not all events go through the same queue? requires investigation
MainQueueName = "main-queue"
// MetadatakeyEventType is the key used for the eventtype in the metadata map of the event
MetadatakeyEventType = "eventtype"
// MetadatakeyEventID is the key used for the eventID in the metadata map of the event
MetadatakeyEventID = "eventid"
// MetadatakeyTraceParent is the key used for the traceparent in the metadata map of the event
MetadatakeyTraceParent = "traceparent"
// MetadatakeyInitiatorID is the key used for the initiator id in the metadata map of the event
MetadatakeyInitiatorID = "initiatorid"
)
type (
// Unmarshaller is the interface events need to fulfill
Unmarshaller interface {
Unmarshal([]byte) (interface{}, error)
}
// Publisher is the interface publishers need to fulfill
Publisher interface {
Publish(string, interface{}, ...events.PublishOption) error
}
// Consumer is the interface consumer need to fulfill
Consumer interface {
Consume(string, ...events.ConsumeOption) (<-chan events.Event, error)
}
// Stream is the interface common to Publisher and Consumer
Stream interface {
Publish(string, interface{}, ...events.PublishOption) error
Consume(string, ...events.ConsumeOption) (<-chan events.Event, error)
}
// Event is the envelope for events
Event struct {
Type string
ID string
TraceParent string
InitiatorID string
Event interface{}
}
)
// Consume returns a channel that will get all events that match the given evs
// group defines the service type: One group will get exactly one copy of a event that is emitted
// NOTE: uses reflect on initialization
func Consume(s Consumer, group string, evs ...Unmarshaller) (<-chan Event, error) {
return ConsumeWithOptions(s, ConsumeOptions{Group: group}, evs...)
}
// ConsumeWithOptions returns a channel that will get all events that match the given evs
// opts defines the options for the consumer
func ConsumeWithOptions(s Consumer, opts ConsumeOptions, evs ...Unmarshaller) (<-chan Event, error) {
o := []events.ConsumeOption{
events.WithGroup(opts.Group),
}
if !opts.AutoAck {
o = append(o, events.WithAutoAck(false, opts.AckWait))
}
c, err := s.Consume(MainQueueName, o...)
if err != nil {
return nil, err
}
registeredEvents := map[string]Unmarshaller{}
for _, e := range evs {
typ := reflect.TypeOf(e)
registeredEvents[typ.String()] = e
}
outchan := make(chan Event)
go func() {
for {
e := <-c
et := e.Metadata[MetadatakeyEventType]
ev, ok := registeredEvents[et]
if !ok {
continue
}
event, err := ev.Unmarshal(e.Payload)
if err != nil {
log.Printf("can't unmarshal event %v", err)
continue
}
outchan <- Event{
Type: et,
ID: e.Metadata[MetadatakeyEventID],
TraceParent: e.Metadata[MetadatakeyTraceParent],
InitiatorID: e.Metadata[MetadatakeyInitiatorID],
Event: event,
}
}
}()
return outchan, nil
}
// ConsumeAll allows consuming all events. Note that unmarshalling must be done manually in this case, therefore Event.Event will always be of type []byte
func ConsumeAll(s Consumer, group string) (<-chan Event, error) {
return ConsumeAllWithOptions(s, ConsumeOptions{Group: group})
}
// ConsumeAllWithOptions allows consuming all events. Note that unmarshalling must be done manually in this case, therefore Event.Event will always be of type []byte
func ConsumeAllWithOptions(s Consumer, opts ConsumeOptions) (<-chan Event, error) {
o := []events.ConsumeOption{
events.WithGroup(opts.Group),
}
if !opts.AutoAck {
o = append(o, events.WithAutoAck(false, opts.AckWait))
}
c, err := s.Consume(MainQueueName, o...)
if err != nil {
return nil, err
}
outchan := make(chan Event)
go func() {
for {
e := <-c
outchan <- Event{
Type: e.Metadata[MetadatakeyEventType],
ID: e.Metadata[MetadatakeyEventID],
TraceParent: e.Metadata[MetadatakeyTraceParent],
InitiatorID: e.Metadata[MetadatakeyInitiatorID],
Event: e.Payload,
}
}
}()
return outchan, nil
}
// Publish publishes the ev to the MainQueue from where it is distributed to all subscribers
// NOTE: needs to use reflect on runtime
func Publish(ctx context.Context, s Publisher, ev interface{}) error {
evName := reflect.TypeOf(ev).String()
traceParent := getTraceParentFromCtx(ctx)
iid, _ := ctxpkg.ContextGetInitiator(ctx)
return s.Publish(MainQueueName, ev, events.WithMetadata(map[string]string{
MetadatakeyEventType: evName,
MetadatakeyEventID: uuid.New().String(),
MetadatakeyTraceParent: traceParent,
MetadatakeyInitiatorID: iid,
}))
}
// GetTraceContext extracts the trace context from the event and injects it into the given
// context.
func (e *Event) GetTraceContext(ctx context.Context) context.Context {
return propagation.TraceContext{}.Extract(ctx, propagation.MapCarrier{
"traceparent": e.TraceParent,
})
}
// getTraceParentFromCtx will return a traceparent from the context if it exists.
// it will be a string as specificied here: https://www.w3.org/TR/trace-context/
// If no trace info in the context, the return will be an empty string
func getTraceParentFromCtx(ctx context.Context) string {
mc := propagation.MapCarrier{}
tc := propagation.TraceContext{}
tc.Inject(ctx, &mc)
return mc["traceparent"]
}
+234
View File
@@ -0,0 +1,234 @@
// Copyright 2018-2022 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package events
import (
"encoding/json"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
)
// ContainerCreated is emitted when a directory has been created
type ContainerCreated struct {
SpaceOwner *user.UserId
Executant *user.UserId
Ref *provider.Reference
ParentID *provider.ResourceId
Owner *user.UserId
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (ContainerCreated) Unmarshal(v []byte) (interface{}, error) {
e := ContainerCreated{}
err := json.Unmarshal(v, &e)
return e, err
}
// FileUploaded is emitted when a file is uploaded
type FileUploaded struct {
SpaceOwner *user.UserId
Executant *user.UserId
Ref *provider.Reference
Owner *user.UserId
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (FileUploaded) Unmarshal(v []byte) (interface{}, error) {
e := FileUploaded{}
err := json.Unmarshal(v, &e)
return e, err
}
// FileTouched is emitted when a file is uploaded
type FileTouched struct {
SpaceOwner *user.UserId
Executant *user.UserId
Ref *provider.Reference
ParentID *provider.ResourceId
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (FileTouched) Unmarshal(v []byte) (interface{}, error) {
e := FileTouched{}
err := json.Unmarshal(v, &e)
return e, err
}
// FileDownloaded is emitted when a file is downloaded
type FileDownloaded struct {
Executant *user.UserId
Ref *provider.Reference
Owner *user.UserId
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (FileDownloaded) Unmarshal(v []byte) (interface{}, error) {
e := FileDownloaded{}
err := json.Unmarshal(v, &e)
return e, err
}
// FileLocked is emitted when a file is locked
type FileLocked struct {
Executant *user.UserId
Ref *provider.Reference
Owner *user.UserId
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (FileLocked) Unmarshal(v []byte) (interface{}, error) {
e := FileLocked{}
err := json.Unmarshal(v, &e)
return e, err
}
// FileUnlocked is emitted when a file is unlocked
type FileUnlocked struct {
Executant *user.UserId
Ref *provider.Reference
Owner *user.UserId
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (FileUnlocked) Unmarshal(v []byte) (interface{}, error) {
e := FileUnlocked{}
err := json.Unmarshal(v, &e)
return e, err
}
// ItemTrashed is emitted when a file or folder is trashed
type ItemTrashed struct {
SpaceOwner *user.UserId
Executant *user.UserId
ID *provider.ResourceId
Ref *provider.Reference
Owner *user.UserId
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (ItemTrashed) Unmarshal(v []byte) (interface{}, error) {
e := ItemTrashed{}
err := json.Unmarshal(v, &e)
return e, err
}
// ItemMoved is emitted when a file or folder is moved
type ItemMoved struct {
SpaceOwner *user.UserId
Executant *user.UserId
Ref *provider.Reference
Owner *user.UserId
OldReference *provider.Reference
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (ItemMoved) Unmarshal(v []byte) (interface{}, error) {
e := ItemMoved{}
err := json.Unmarshal(v, &e)
return e, err
}
// TrashbinPurged is emitted when the whole trashbin is purged
type TrashbinPurged struct {
Executant *user.UserId
Ref *provider.Reference
Owner *user.UserId
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (TrashbinPurged) Unmarshal(v []byte) (interface{}, error) {
e := TrashbinPurged{}
err := json.Unmarshal(v, &e)
return e, err
}
// ItemPurged is emitted when a file or folder is removed from trashbin
type ItemPurged struct {
Executant *user.UserId
ID *provider.ResourceId
Ref *provider.Reference
Owner *user.UserId
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (ItemPurged) Unmarshal(v []byte) (interface{}, error) {
e := ItemPurged{}
err := json.Unmarshal(v, &e)
return e, err
}
// ItemRestored is emitted when a file or folder is restored from trashbin
type ItemRestored struct {
SpaceOwner *user.UserId
Executant *user.UserId
ID *provider.ResourceId
Ref *provider.Reference
Owner *user.UserId
OldReference *provider.Reference
Key string
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (ItemRestored) Unmarshal(v []byte) (interface{}, error) {
e := ItemRestored{}
err := json.Unmarshal(v, &e)
return e, err
}
// FileVersionRestored is emitted when a file version is restored
type FileVersionRestored struct {
SpaceOwner *user.UserId
Executant *user.UserId
Ref *provider.Reference
Owner *user.UserId
Key string
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (FileVersionRestored) Unmarshal(v []byte) (interface{}, error) {
e := FileVersionRestored{}
err := json.Unmarshal(v, &e)
return e, err
}
+106
View File
@@ -0,0 +1,106 @@
// Copyright 2018-2022 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package events
import (
"encoding/json"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
)
// GroupCreated is emitted when a group was created
type GroupCreated struct {
Executant *user.UserId
GroupID string
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (GroupCreated) Unmarshal(v []byte) (interface{}, error) {
e := GroupCreated{}
err := json.Unmarshal(v, &e)
return e, err
}
// GroupDeleted is emitted when a group was deleted
type GroupDeleted struct {
Executant *user.UserId
GroupID string
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (GroupDeleted) Unmarshal(v []byte) (interface{}, error) {
e := GroupDeleted{}
err := json.Unmarshal(v, &e)
return e, err
}
// GroupMemberAdded is emitted when a user was added to a group
type GroupMemberAdded struct {
Executant *user.UserId
GroupID string
UserID string
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (GroupMemberAdded) Unmarshal(v []byte) (interface{}, error) {
e := GroupMemberAdded{}
err := json.Unmarshal(v, &e)
return e, err
}
// GroupMemberRemoved is emitted when a user was removed from a group
type GroupMemberRemoved struct {
Executant *user.UserId
GroupID string
UserID string
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (GroupMemberRemoved) Unmarshal(v []byte) (interface{}, error) {
e := GroupMemberRemoved{}
err := json.Unmarshal(v, &e)
return e, err
}
// GroupFeature represents a group feature
type GroupFeature struct {
Name string
Value string
Timestamp *types.Timestamp
}
// GroupFeatureChanged is emitted when a group feature was changed
type GroupFeatureChanged struct {
Executant *user.UserId
GroupID string
Features []GroupFeature
Timestamp *types.Timestamp
}
// Unmarshal to fulfill unmarshaller interface
func (GroupFeatureChanged) Unmarshal(v []byte) (interface{}, error) {
e := GroupFeatureChanged{}
err := json.Unmarshal(v, &e)
return e, err
}
+44
View File
@@ -0,0 +1,44 @@
// Copyright 2026 OpenCloud GmbH <mail@opencloud.eu>
// SPDX-License-Identifier: Apache-2.0
package events
import (
"encoding/json"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
)
// LabelAdded is emitted when a user adds a label to a resource
type LabelAdded struct {
Ref *provider.Reference
Label string
Executant *user.UserId
UserID *user.UserId
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (LabelAdded) Unmarshal(v []byte) (interface{}, error) {
e := LabelAdded{}
err := json.Unmarshal(v, &e)
return e, err
}
// LabelRemoved is emitted when a user removes a label from a resource
type LabelRemoved struct {
Ref *provider.Reference
Label string
Executant *user.UserId
UserID *user.UserId
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (LabelRemoved) Unmarshal(v []byte) (interface{}, error) {
e := LabelRemoved{}
err := json.Unmarshal(v, &e)
return e, err
}
@@ -0,0 +1,186 @@
// Copyright 2018-2022 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
// Code generated by mockery v2.53.2. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
events "go-micro.dev/v4/events"
)
// Stream is an autogenerated mock type for the Stream type
type Stream struct {
mock.Mock
}
type Stream_Expecter struct {
mock *mock.Mock
}
func (_m *Stream) EXPECT() *Stream_Expecter {
return &Stream_Expecter{mock: &_m.Mock}
}
// Consume provides a mock function with given fields: _a0, _a1
func (_m *Stream) Consume(_a0 string, _a1 ...events.ConsumeOption) (<-chan events.Event, error) {
var tmpRet mock.Arguments
if len(_a1) > 0 {
tmpRet = _m.Called(_a0, _a1)
} else {
tmpRet = _m.Called(_a0)
}
ret := tmpRet
if len(ret) == 0 {
panic("no return value specified for Consume")
}
var r0 <-chan events.Event
var r1 error
if rf, ok := ret.Get(0).(func(string, ...events.ConsumeOption) (<-chan events.Event, error)); ok {
return rf(_a0, _a1...)
}
if rf, ok := ret.Get(0).(func(string, ...events.ConsumeOption) <-chan events.Event); ok {
r0 = rf(_a0, _a1...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(<-chan events.Event)
}
}
if rf, ok := ret.Get(1).(func(string, ...events.ConsumeOption) error); ok {
r1 = rf(_a0, _a1...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Stream_Consume_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Consume'
type Stream_Consume_Call struct {
*mock.Call
}
// Consume is a helper method to define mock.On call
// - _a0 string
// - _a1 ...events.ConsumeOption
func (_e *Stream_Expecter) Consume(_a0 interface{}, _a1 ...interface{}) *Stream_Consume_Call {
return &Stream_Consume_Call{Call: _e.mock.On("Consume",
append([]interface{}{_a0}, _a1...)...)}
}
func (_c *Stream_Consume_Call) Run(run func(_a0 string, _a1 ...events.ConsumeOption)) *Stream_Consume_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]events.ConsumeOption, len(args)-1)
for i, a := range args[1:] {
if a != nil {
variadicArgs[i] = a.(events.ConsumeOption)
}
}
run(args[0].(string), variadicArgs...)
})
return _c
}
func (_c *Stream_Consume_Call) Return(_a0 <-chan events.Event, _a1 error) *Stream_Consume_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *Stream_Consume_Call) RunAndReturn(run func(string, ...events.ConsumeOption) (<-chan events.Event, error)) *Stream_Consume_Call {
_c.Call.Return(run)
return _c
}
// Publish provides a mock function with given fields: _a0, _a1, _a2
func (_m *Stream) Publish(_a0 string, _a1 interface{}, _a2 ...events.PublishOption) error {
var tmpRet mock.Arguments
if len(_a2) > 0 {
tmpRet = _m.Called(_a0, _a1, _a2)
} else {
tmpRet = _m.Called(_a0, _a1)
}
ret := tmpRet
if len(ret) == 0 {
panic("no return value specified for Publish")
}
var r0 error
if rf, ok := ret.Get(0).(func(string, interface{}, ...events.PublishOption) error); ok {
r0 = rf(_a0, _a1, _a2...)
} else {
r0 = ret.Error(0)
}
return r0
}
// Stream_Publish_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Publish'
type Stream_Publish_Call struct {
*mock.Call
}
// Publish is a helper method to define mock.On call
// - _a0 string
// - _a1 interface{}
// - _a2 ...events.PublishOption
func (_e *Stream_Expecter) Publish(_a0 interface{}, _a1 interface{}, _a2 ...interface{}) *Stream_Publish_Call {
return &Stream_Publish_Call{Call: _e.mock.On("Publish",
append([]interface{}{_a0, _a1}, _a2...)...)}
}
func (_c *Stream_Publish_Call) Run(run func(_a0 string, _a1 interface{}, _a2 ...events.PublishOption)) *Stream_Publish_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]events.PublishOption, len(args)-2)
for i, a := range args[2:] {
if a != nil {
variadicArgs[i] = a.(events.PublishOption)
}
}
run(args[0].(string), args[1].(interface{}), variadicArgs...)
})
return _c
}
func (_c *Stream_Publish_Call) Return(_a0 error) *Stream_Publish_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *Stream_Publish_Call) RunAndReturn(run func(string, interface{}, ...events.PublishOption) error) *Stream_Publish_Call {
_c.Call.Return(run)
return _c
}
// NewStream creates a new instance of Stream. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewStream(t interface {
mock.TestingT
Cleanup(func())
}) *Stream {
mock := &Stream{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
@@ -0,0 +1,17 @@
package events
import (
"encoding/json"
)
// SendEmailsEvent instructs the notification service to send grouped emails
type SendEmailsEvent struct {
Interval string
}
// Unmarshal to fulfill umarshaller interface
func (SendEmailsEvent) Unmarshal(v []byte) (interface{}, error) {
e := SendEmailsEvent{}
err := json.Unmarshal(v, &e)
return e, err
}
+46
View File
@@ -0,0 +1,46 @@
// Copyright 2018-2024 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package events
import (
"encoding/json"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
)
// OCMCoreShareCreated is emitted when an ocm share is received
type OCMCoreShareCreated struct {
ShareID string
Executant *user.UserId
Sharer *user.UserId
GranteeUserID *user.UserId
ItemID string
ResourceName string
Permissions *provider.ResourcePermissions
CTime *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (OCMCoreShareCreated) Unmarshal(v []byte) (interface{}, error) {
e := OCMCoreShareCreated{}
err := json.Unmarshal(v, &e)
return e, err
}
+12
View File
@@ -0,0 +1,12 @@
package events
import (
"time"
)
// ConsumeOptions contains all the options which can be provided when consuming events
type ConsumeOptions struct {
Group string
AutoAck bool
AckWait time.Duration
}
@@ -0,0 +1,226 @@
// Copyright 2018-2022 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package events
import (
"encoding/json"
"time"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
)
type (
// Postprocessingstep are the available postprocessingsteps
Postprocessingstep string
// PostprocessingOutcome defines the result of the postprocessing
PostprocessingOutcome string
)
var (
// PPStepAntivirus is the step that scans for viruses
PPStepAntivirus Postprocessingstep = "virusscan"
// PPStepPolicies is the step the step that enforces policies
PPStepPolicies Postprocessingstep = "policies"
// PPStepDelay is the step that processing. Useful for testing or user annoyment
PPStepDelay Postprocessingstep = "delay"
// PPStepFinished is the step that signals that postprocessing is finished, but storage provider hasn't acknowledged it yet
PPStepFinished Postprocessingstep = "finished"
// PPOutcomeDelete means that the file and the upload should be deleted
PPOutcomeDelete PostprocessingOutcome = "delete"
// PPOutcomeAbort means that the upload is cancelled but the bytes are being kept in the upload folder
PPOutcomeAbort PostprocessingOutcome = "abort"
// PPOutcomeContinue means that the upload is moved to its final destination (eventually being marked with pp results)
PPOutcomeContinue PostprocessingOutcome = "continue"
// PPOutcomeRetry means that there was a temporary issue and the postprocessing should be retried at a later point in time
PPOutcomeRetry PostprocessingOutcome = "retry"
)
// BytesReceived is emitted by the server when it received all bytes of an upload
type BytesReceived struct {
UploadID string
SpaceOwner *user.UserId
ExecutingUser *user.User
ResourceID *provider.ResourceId
Filename string
Filesize uint64
URL string
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (BytesReceived) Unmarshal(v []byte) (interface{}, error) {
e := BytesReceived{}
err := json.Unmarshal(v, &e)
return e, err
}
// StartPostprocessingStep can be issued by the server to start a postprocessing step
type StartPostprocessingStep struct {
UploadID string
URL string
ExecutingUser *user.User
Filename string
Filesize uint64
Token string // for file retrieval in after upload case
ResourceID *provider.ResourceId // for file retrieval in after upload case
RevaToken string // for file retrieval in after upload case
StepToStart Postprocessingstep
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (StartPostprocessingStep) Unmarshal(v []byte) (interface{}, error) {
e := StartPostprocessingStep{}
err := json.Unmarshal(v, &e)
return e, err
}
// PostprocessingStepFinished can be issued by the server when a postprocessing step is finished
type PostprocessingStepFinished struct {
UploadID string
ExecutingUser *user.User
Filename string
FinishedStep Postprocessingstep // name of the step
Result interface{} // result information see VirusscanResult for example
Error error // possible error of the step
Outcome PostprocessingOutcome // some services may cause postprocessing to stop
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (PostprocessingStepFinished) Unmarshal(v []byte) (interface{}, error) {
e := PostprocessingStepFinished{}
err := json.Unmarshal(v, &e)
if err != nil {
return nil, err
}
switch e.FinishedStep {
case PPStepAntivirus:
var res VirusscanResult
b, _ := json.Marshal(e.Result)
err = json.Unmarshal(b, &res)
e.Result = res
case PPStepPolicies:
// nothing to do, but this makes the linter happy
}
return e, err
}
// VirusscanResult is the Result of a PostprocessingStepFinished event from the antivirus
type VirusscanResult struct {
Infected bool
Description string
Scandate time.Time
ResourceID *provider.ResourceId
ErrorMsg string // empty when no error
Timestamp *types.Timestamp
}
// PostprocessingFinished is emitted by *some* service which can decide that
type PostprocessingFinished struct {
UploadID string
Filename string
SpaceOwner *user.UserId
ExecutingUser *user.User
Result map[Postprocessingstep]interface{} // it is a map[step]Event
Outcome PostprocessingOutcome
Timestamp *types.Timestamp
ImpersonatingUser *user.User
}
// Unmarshal to fulfill umarshaller interface
func (PostprocessingFinished) Unmarshal(v []byte) (interface{}, error) {
e := PostprocessingFinished{}
err := json.Unmarshal(v, &e)
return e, err
}
// PostprocessingRetry is emitted by *some* service which can decide that
type PostprocessingRetry struct {
UploadID string
Filename string
ExecutingUser *user.User
Failures int
BackoffDuration time.Duration
}
// Unmarshal to fulfill umarshaller interface
func (PostprocessingRetry) Unmarshal(v []byte) (interface{}, error) {
e := PostprocessingRetry{}
err := json.Unmarshal(v, &e)
return e, err
}
// UploadReady is emitted by the storage provider when postprocessing is finished
type UploadReady struct {
UploadID string
Filename string
SpaceOwner *user.UserId
ExecutingUser *user.User
ImpersonatingUser *user.User
FileRef *provider.Reference
ParentID *provider.ResourceId
Timestamp *types.Timestamp
Failed bool
IsVersion bool
// add reference here? We could use it to inform client pp is finished
}
// Unmarshal to fulfill umarshaller interface
func (UploadReady) Unmarshal(v []byte) (interface{}, error) {
e := UploadReady{}
err := json.Unmarshal(v, &e)
return e, err
}
// ResumePostprocessing can be emitted to repair broken postprocessing
type ResumePostprocessing struct {
UploadID string
Step Postprocessingstep
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (ResumePostprocessing) Unmarshal(v []byte) (interface{}, error) {
e := ResumePostprocessing{}
err := json.Unmarshal(v, &e)
return e, err
}
// RestartPostprocessing will be emitted by postprocessing service if it doesn't know about an upload
type RestartPostprocessing struct {
UploadID string
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (RestartPostprocessing) Unmarshal(v []byte) (interface{}, error) {
e := RestartPostprocessing{}
err := json.Unmarshal(v, &e)
return e, err
}
+27
View File
@@ -0,0 +1,27 @@
package raw
import (
"bytes"
"crypto/x509"
"errors"
"io"
)
// newCertPoolFromPEM reads certificates from io.Reader and returns a x509.CertPool
// containing those certificates.
func newCertPoolFromPEM(crts ...io.Reader) (*x509.CertPool, error) {
certPool := x509.NewCertPool()
var buf bytes.Buffer
for _, c := range crts {
if _, err := io.Copy(&buf, c); err != nil {
return nil, err
}
if !certPool.AppendCertsFromPEM(buf.Bytes()) {
return nil, errors.New("failed to append cert from PEM")
}
buf.Reset()
}
return certPool, nil
}
@@ -0,0 +1,176 @@
// Copyright 2018-2022 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
// Code generated by mockery v2.53.2. DO NOT EDIT.
package mocks
import (
jetstream "github.com/nats-io/nats.go/jetstream"
events "github.com/opencloud-eu/reva/v2/pkg/events"
mock "github.com/stretchr/testify/mock"
raw "github.com/opencloud-eu/reva/v2/pkg/events/raw"
)
// Stream is an autogenerated mock type for the Stream type
type Stream struct {
mock.Mock
}
type Stream_Expecter struct {
mock *mock.Mock
}
func (_m *Stream) EXPECT() *Stream_Expecter {
return &Stream_Expecter{mock: &_m.Mock}
}
// Consume provides a mock function with given fields: group, evs
func (_m *Stream) Consume(group string, evs ...events.Unmarshaller) (<-chan raw.Event, error) {
var tmpRet mock.Arguments
if len(evs) > 0 {
tmpRet = _m.Called(group, evs)
} else {
tmpRet = _m.Called(group)
}
ret := tmpRet
if len(ret) == 0 {
panic("no return value specified for Consume")
}
var r0 <-chan raw.Event
var r1 error
if rf, ok := ret.Get(0).(func(string, ...events.Unmarshaller) (<-chan raw.Event, error)); ok {
return rf(group, evs...)
}
if rf, ok := ret.Get(0).(func(string, ...events.Unmarshaller) <-chan raw.Event); ok {
r0 = rf(group, evs...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(<-chan raw.Event)
}
}
if rf, ok := ret.Get(1).(func(string, ...events.Unmarshaller) error); ok {
r1 = rf(group, evs...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Stream_Consume_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Consume'
type Stream_Consume_Call struct {
*mock.Call
}
// Consume is a helper method to define mock.On call
// - group string
// - evs ...events.Unmarshaller
func (_e *Stream_Expecter) Consume(group interface{}, evs ...interface{}) *Stream_Consume_Call {
return &Stream_Consume_Call{Call: _e.mock.On("Consume",
append([]interface{}{group}, evs...)...)}
}
func (_c *Stream_Consume_Call) Run(run func(group string, evs ...events.Unmarshaller)) *Stream_Consume_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]events.Unmarshaller, len(args)-1)
for i, a := range args[1:] {
if a != nil {
variadicArgs[i] = a.(events.Unmarshaller)
}
}
run(args[0].(string), variadicArgs...)
})
return _c
}
func (_c *Stream_Consume_Call) Return(_a0 <-chan raw.Event, _a1 error) *Stream_Consume_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *Stream_Consume_Call) RunAndReturn(run func(string, ...events.Unmarshaller) (<-chan raw.Event, error)) *Stream_Consume_Call {
_c.Call.Return(run)
return _c
}
// JetStream provides a mock function with no fields
func (_m *Stream) JetStream() jetstream.Stream {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for JetStream")
}
var r0 jetstream.Stream
if rf, ok := ret.Get(0).(func() jetstream.Stream); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(jetstream.Stream)
}
}
return r0
}
// Stream_JetStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'JetStream'
type Stream_JetStream_Call struct {
*mock.Call
}
// JetStream is a helper method to define mock.On call
func (_e *Stream_Expecter) JetStream() *Stream_JetStream_Call {
return &Stream_JetStream_Call{Call: _e.mock.On("JetStream")}
}
func (_c *Stream_JetStream_Call) Run(run func()) *Stream_JetStream_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *Stream_JetStream_Call) Return(_a0 jetstream.Stream) *Stream_JetStream_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *Stream_JetStream_Call) RunAndReturn(run func() jetstream.Stream) *Stream_JetStream_Call {
_c.Call.Return(run)
return _c
}
// NewStream creates a new instance of Stream. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewStream(t interface {
mock.TestingT
Cleanup(func())
}) *Stream {
mock := &Stream{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
+225
View File
@@ -0,0 +1,225 @@
package raw
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"os"
"reflect"
"time"
"github.com/cenkalti/backoff"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
"github.com/opencloud-eu/reva/v2/pkg/events"
"github.com/pkg/errors"
)
// Config is the configuration needed for a NATS event stream
type Config struct {
Endpoint string `mapstructure:"address"` // Endpoint of the nats server
Cluster string `mapstructure:"clusterID"` // CluserID of the nats cluster
TLSInsecure bool `mapstructure:"tls-insecure"` // Whether to verify TLS certificates
TLSRootCACertificate string `mapstructure:"tls-root-ca-cert"` // The root CA certificate used to validate the TLS certificate
EnableTLS bool `mapstructure:"enable-tls"` // Enable TLS
AuthUsername string `mapstructure:"username"` // Username for authentication
AuthPassword string `mapstructure:"password"` // Password for authentication
MaxAckPending int `mapstructure:"max-ack-pending"` // Maximum number of unacknowledged messages
AckWait time.Duration `mapstructure:"ack-wait"` // Time to wait for an ack
}
type RawEvent struct {
Timestamp time.Time
Metadata map[string]string
ID string
Topic string
Payload []byte
msg jetstream.Msg
}
type Event struct {
events.Event
msg jetstream.Msg
}
func (re *Event) Ack() error {
if re.msg == nil {
return errors.New("cannot ack event without message")
}
return re.msg.Ack()
}
func (re *Event) InProgress() error {
if re.msg == nil {
return errors.New("cannot mark event as in progress without message")
}
return re.msg.InProgress()
}
type Stream interface {
Consume(group string, evs ...events.Unmarshaller) (<-chan Event, error)
JetStream() jetstream.Stream
}
type RawStream struct {
js jetstream.Stream
c Config
}
func JetStream(ctx context.Context, name string, cfg Config) (jetstream.JetStream, error) {
var js jetstream.JetStream
connect := func() error {
var tlsConf *tls.Config
if cfg.EnableTLS {
var rootCAPool *x509.CertPool
if cfg.TLSRootCACertificate != "" {
rootCrtFile, err := os.Open(cfg.TLSRootCACertificate)
if err != nil {
return err
}
rootCAPool, err = newCertPoolFromPEM(rootCrtFile)
if err != nil {
return err
}
cfg.TLSInsecure = false
}
tlsConf = &tls.Config{
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: cfg.TLSInsecure,
RootCAs: rootCAPool,
}
}
nopts := nats.GetDefaultOptions()
nopts.Name = name
if tlsConf != nil {
nopts.Secure = true
nopts.TLSConfig = tlsConf
}
if len(cfg.Endpoint) > 0 {
nopts.Servers = []string{cfg.Endpoint}
}
if cfg.AuthUsername != "" && cfg.AuthPassword != "" {
nopts.User = cfg.AuthUsername
nopts.Password = cfg.AuthPassword
}
conn, err := nopts.Connect()
if err != nil {
return err
}
js, err = jetstream.New(conn)
return err
}
err := backoff.Retry(connect, backoff.NewExponentialBackOff())
if err != nil {
return nil, errors.Wrap(err, "could not connect to nats jetstream")
}
return js, nil
}
func FromConfig(ctx context.Context, name string, cfg Config) (Stream, error) {
jsConn, err := JetStream(ctx, name, cfg)
if err != nil {
return nil, err
}
js, err := jsConn.Stream(ctx, events.MainQueueName)
if err != nil {
return nil, err
}
return &RawStream{
js: js,
c: cfg,
}, nil
}
func (s *RawStream) Consume(group string, evs ...events.Unmarshaller) (<-chan Event, error) {
c, err := s.consumeRaw(group)
if err != nil {
return nil, err
}
registeredEvents := map[string]events.Unmarshaller{}
for _, e := range evs {
typ := reflect.TypeOf(e)
registeredEvents[typ.String()] = e
}
outchan := make(chan Event)
go func() {
for {
e := <-c
eventType := e.Metadata[events.MetadatakeyEventType]
ev, ok := registeredEvents[eventType]
if !ok {
_ = e.msg.Ack() // Discard. We are not interested in this event type
continue
}
event, err := ev.Unmarshal(e.Payload)
if err != nil {
continue
}
outchan <- Event{
Event: events.Event{
Type: eventType,
ID: e.Metadata[events.MetadatakeyEventID],
TraceParent: e.Metadata[events.MetadatakeyTraceParent],
InitiatorID: e.Metadata[events.MetadatakeyInitiatorID],
Event: event,
},
msg: e.msg,
}
}
}()
return outchan, nil
}
func (s *RawStream) consumeRaw(group string) (<-chan RawEvent, error) {
consumer, err := s.js.CreateOrUpdateConsumer(context.Background(), jetstream.ConsumerConfig{
Durable: group,
DeliverPolicy: jetstream.DeliverNewPolicy,
AckPolicy: jetstream.AckExplicitPolicy, // Require manual acknowledgment
MaxAckPending: s.c.MaxAckPending, // Maximum number of unacknowledged messages
AckWait: s.c.AckWait, // Time to wait for an ack
})
if err != nil {
return nil, err
}
channel := make(chan RawEvent)
callback := func(msg jetstream.Msg) {
var rawEvent RawEvent
if err := json.Unmarshal(msg.Data(), &rawEvent); err != nil {
fmt.Printf("error unmarshalling event: %v\n", err)
return
}
rawEvent.msg = msg
channel <- rawEvent
}
_, err = consumer.Consume(callback)
if err != nil {
return nil, err
}
return channel, nil
}
func (s *RawStream) JetStream() jetstream.Stream {
return s.js
}
@@ -0,0 +1,26 @@
package events
import (
"encoding/json"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
)
// ScienceMeshInviteTokenGenerated is emitted when a sciencemesh token is generated
type ScienceMeshInviteTokenGenerated struct {
Sharer *user.UserId
RecipientMail string
Token string
Description string
Expiration uint64
InviteLink string
Timestamp *types.Timestamp
}
// Unmarshal to fulfill unmarshaller interface
func (ScienceMeshInviteTokenGenerated) Unmarshal(v []byte) (interface{}, error) {
e := ScienceMeshInviteTokenGenerated{}
err := json.Unmarshal(v, &e)
return e, err
}
+244
View File
@@ -0,0 +1,244 @@
// Copyright 2018-2021 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package events
import (
"encoding/json"
"time"
group "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
)
// ShareCreated is emitted when a share is created
type ShareCreated struct {
ShareID *collaboration.ShareId
Executant *user.UserId
Sharer *user.UserId
// split the protobuf Grantee oneof so we can use stdlib encoding/json
GranteeUserID *user.UserId
GranteeGroupID *group.GroupId
Sharee *provider.Grantee
ItemID *provider.ResourceId
ResourceName string
Permissions *collaboration.SharePermissions
CTime *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (ShareCreated) Unmarshal(v []byte) (interface{}, error) {
e := ShareCreated{}
err := json.Unmarshal(v, &e)
return e, err
}
// ShareRemoved is emitted when a share is removed
type ShareRemoved struct {
Executant *user.UserId
// split protobuf Spec
ShareID *collaboration.ShareId
ShareKey *collaboration.ShareKey
// split the protobuf Grantee oneof so we can use stdlib encoding/json
GranteeUserID *user.UserId
GranteeGroupID *group.GroupId
ItemID *provider.ResourceId
ResourceName string
Timestamp time.Time
}
// Unmarshal to fulfill umarshaller interface
func (ShareRemoved) Unmarshal(v []byte) (interface{}, error) {
e := ShareRemoved{}
err := json.Unmarshal(v, &e)
return e, err
}
// ShareUpdated is emitted when a share is updated
type ShareUpdated struct {
Executant *user.UserId
ShareID *collaboration.ShareId
ItemID *provider.ResourceId
ResourceName string
Permissions *collaboration.SharePermissions
GranteeUserID *user.UserId
GranteeGroupID *group.GroupId
Sharer *user.UserId
MTime *types.Timestamp
Updated string // Deprecated
// indicates what was updated
UpdateMask []string
}
// Unmarshal to fulfill umarshaller interface
func (ShareUpdated) Unmarshal(v []byte) (interface{}, error) {
e := ShareUpdated{}
err := json.Unmarshal(v, &e)
return e, err
}
// ShareExpired is emitted when a share expires
type ShareExpired struct {
ShareID *collaboration.ShareId
ShareOwner *user.UserId
ItemID *provider.ResourceId
Path string
ExpiredAt time.Time
// split the protobuf Grantee oneof so we can use stdlib encoding/json
GranteeUserID *user.UserId
GranteeGroupID *group.GroupId
}
// Unmarshal to fulfill umarshaller interface
func (ShareExpired) Unmarshal(v []byte) (interface{}, error) {
e := ShareExpired{}
err := json.Unmarshal(v, &e)
return e, err
}
// ReceivedShareUpdated is emitted when a received share is accepted or declined
type ReceivedShareUpdated struct {
Executant *user.UserId
ShareID *collaboration.ShareId
ItemID *provider.ResourceId
Path string
Permissions *collaboration.SharePermissions
GranteeUserID *user.UserId
GranteeGroupID *group.GroupId
Sharer *user.UserId
MTime *types.Timestamp
State string
}
// Unmarshal to fulfill umarshaller interface
func (ReceivedShareUpdated) Unmarshal(v []byte) (interface{}, error) {
e := ReceivedShareUpdated{}
err := json.Unmarshal(v, &e)
return e, err
}
// LinkCreated is emitted when a public link is created
type LinkCreated struct {
Executant *user.UserId
ShareID *link.PublicShareId
Sharer *user.UserId
ItemID *provider.ResourceId
ResourceName string
Permissions *link.PublicSharePermissions
DisplayName string
Expiration *types.Timestamp
PasswordProtected bool
CTime *types.Timestamp
Token string
}
// Unmarshal to fulfill umarshaller interface
func (LinkCreated) Unmarshal(v []byte) (interface{}, error) {
e := LinkCreated{}
err := json.Unmarshal(v, &e)
return e, err
}
// LinkUpdated is emitted when a public link is updated
type LinkUpdated struct {
Executant *user.UserId
ShareID *link.PublicShareId
Sharer *user.UserId
ItemID *provider.ResourceId
ResourceName string
Permissions *link.PublicSharePermissions
DisplayName string
Expiration *types.Timestamp
PasswordProtected bool
MTime *types.Timestamp
Token string
FieldUpdated string
}
// Unmarshal to fulfill umarshaller interface
func (LinkUpdated) Unmarshal(v []byte) (interface{}, error) {
e := LinkUpdated{}
err := json.Unmarshal(v, &e)
return e, err
}
// LinkAccessed is emitted when a public link is accessed successfully (by token)
type LinkAccessed struct {
Executant *user.UserId
ShareID *link.PublicShareId
Sharer *user.UserId
ItemID *provider.ResourceId
Path string
Permissions *link.PublicSharePermissions
DisplayName string
Expiration *types.Timestamp
PasswordProtected bool
CTime *types.Timestamp
Token string
}
// Unmarshal to fulfill umarshaller interface
func (LinkAccessed) Unmarshal(v []byte) (interface{}, error) {
e := LinkAccessed{}
err := json.Unmarshal(v, &e)
return e, err
}
// LinkAccessFailed is emitted when an access to a public link has resulted in an error (by token)
type LinkAccessFailed struct {
Executant *user.UserId
ShareID *link.PublicShareId
Token string
Status rpc.Code
Message string
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (LinkAccessFailed) Unmarshal(v []byte) (interface{}, error) {
e := LinkAccessFailed{}
err := json.Unmarshal(v, &e)
return e, err
}
// LinkRemoved is emitted when a share is removed
type LinkRemoved struct {
Executant *user.UserId
// split protobuf Ref
ShareID *link.PublicShareId
ShareToken string
Timestamp *types.Timestamp
ItemID *provider.ResourceId
ResourceName string
}
// Unmarshal to fulfill umarshaller interface
func (LinkRemoved) Unmarshal(v []byte) (interface{}, error) {
e := LinkRemoved{}
err := json.Unmarshal(v, &e)
return e, err
}
+192
View File
@@ -0,0 +1,192 @@
// Copyright 2018-2022 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package events
import (
"encoding/json"
"time"
group "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
)
// SpaceCreated is emitted when a space is created
type SpaceCreated struct {
Executant *user.UserId
ID *provider.StorageSpaceId
Owner *user.UserId
Root *provider.ResourceId
Name string
Type string
Quota *provider.Quota
MTime *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (SpaceCreated) Unmarshal(v []byte) (interface{}, error) {
e := SpaceCreated{}
err := json.Unmarshal(v, &e)
return e, err
}
// SpaceRenamed is emitted when a space is renamed
type SpaceRenamed struct {
Executant *user.UserId
ID *provider.StorageSpaceId
Owner *user.UserId
Name string
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (SpaceRenamed) Unmarshal(v []byte) (interface{}, error) {
e := SpaceRenamed{}
err := json.Unmarshal(v, &e)
return e, err
}
// SpaceDisabled is emitted when a space is disabled
type SpaceDisabled struct {
Executant *user.UserId
ID *provider.StorageSpaceId
Timestamp time.Time
}
// Unmarshal to fulfill umarshaller interface
func (SpaceDisabled) Unmarshal(v []byte) (interface{}, error) {
e := SpaceDisabled{}
err := json.Unmarshal(v, &e)
return e, err
}
// SpaceEnabled is emitted when a space is (re-)enabled
type SpaceEnabled struct {
Executant *user.UserId
ID *provider.StorageSpaceId
Owner *user.UserId
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (SpaceEnabled) Unmarshal(v []byte) (interface{}, error) {
e := SpaceEnabled{}
err := json.Unmarshal(v, &e)
return e, err
}
// SpaceDeleted is emitted when a space is deleted
type SpaceDeleted struct {
Executant *user.UserId
ID *provider.StorageSpaceId
SpaceName string
FinalMembers map[string]provider.ResourcePermissions
Timestamp time.Time
}
// Unmarshal to fulfill umarshaller interface
func (SpaceDeleted) Unmarshal(v []byte) (interface{}, error) {
e := SpaceDeleted{}
err := json.Unmarshal(v, &e)
return e, err
}
// SpaceShared is emitted when a space is shared
type SpaceShared struct {
Executant *user.UserId
GranteeUserID *user.UserId
GranteeGroupID *group.GroupId
Creator *user.UserId
ID *provider.StorageSpaceId
Timestamp time.Time
}
// Unmarshal to fulfill umarshaller interface
func (SpaceShared) Unmarshal(v []byte) (interface{}, error) {
e := SpaceShared{}
err := json.Unmarshal(v, &e)
return e, err
}
// SpaceShareUpdated is emitted when a space share is updated
type SpaceShareUpdated struct {
Executant *user.UserId
GranteeUserID *user.UserId
GranteeGroupID *group.GroupId
ID *provider.StorageSpaceId
Timestamp time.Time
}
// Unmarshal to fulfill umarshaller interface
func (SpaceShareUpdated) Unmarshal(v []byte) (interface{}, error) {
ev := SpaceShareUpdated{}
err := json.Unmarshal(v, &ev)
return ev, err
}
// SpaceUnshared is emitted when a space is unshared
type SpaceUnshared struct {
Executant *user.UserId
GranteeUserID *user.UserId
GranteeGroupID *group.GroupId
ID *provider.StorageSpaceId
Timestamp time.Time
}
// Unmarshal to fulfill umarshaller interface
func (SpaceUnshared) Unmarshal(v []byte) (interface{}, error) {
e := SpaceUnshared{}
err := json.Unmarshal(v, &e)
return e, err
}
// SpaceUpdated is emitted when a space is updated
type SpaceUpdated struct {
Executant *user.UserId
ID *provider.StorageSpaceId
Space *provider.StorageSpace
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (SpaceUpdated) Unmarshal(v []byte) (interface{}, error) {
e := SpaceUpdated{}
err := json.Unmarshal(v, &e)
return e, err
}
// SpaceMembershipExpired is emitted when a space membership expires
type SpaceMembershipExpired struct {
SpaceOwner *user.UserId
SpaceID *provider.StorageSpaceId
SpaceName string
ExpiredAt time.Time
// split the protobuf Grantee oneof so we can use stdlib encoding/json
GranteeUserID *user.UserId
GranteeGroupID *group.GroupId
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (SpaceMembershipExpired) Unmarshal(v []byte) (interface{}, error) {
e := SpaceMembershipExpired{}
err := json.Unmarshal(v, &e)
return e, err
}
+19
View File
@@ -0,0 +1,19 @@
package events
import (
"encoding/json"
)
// SendSSE instructs the sse service to send one or multiple notifications
type SendSSE struct {
UserIDs []string
Type string
Message []byte
}
// Unmarshal to fulfill umarshaller interface
func (SendSSE) Unmarshal(v []byte) (interface{}, error) {
e := SendSSE{}
err := json.Unmarshal(v, &e)
return e, err
}
+141
View File
@@ -0,0 +1,141 @@
package stream
import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"errors"
"io"
"os"
"time"
"github.com/cenkalti/backoff"
"github.com/go-micro/plugins/v4/events/natsjs"
"github.com/nats-io/nats.go/jetstream"
"github.com/opencloud-eu/reva/v2/pkg/events"
"github.com/opencloud-eu/reva/v2/pkg/events/raw"
"github.com/opencloud-eu/reva/v2/pkg/logger"
)
// NatsConfig is the configuration needed for a NATS event stream
type NatsConfig struct {
Endpoint string `mapstructure:"address"` // Endpoint of the nats server
Cluster string `mapstructure:"clusterID"` // CluserID of the nats cluster
TLSInsecure bool `mapstructure:"tls-insecure"` // Whether to verify TLS certificates
TLSRootCACertificate string `mapstructure:"tls-root-ca-cert"` // The root CA certificate used to validate the TLS certificate
EnableTLS bool `mapstructure:"enable-tls"` // Enable TLS
AuthUsername string `mapstructure:"username"` // Username for authentication
AuthPassword string `mapstructure:"password"` // Password for authentication
}
// NatsFromConfig returns a nats stream from the given config
func NatsFromConfig(connName string, disableDurability bool, cfg NatsConfig) (events.Stream, error) {
var tlsConf *tls.Config
if cfg.EnableTLS {
var rootCAPool *x509.CertPool
if cfg.TLSRootCACertificate != "" {
rootCrtFile, err := os.Open(cfg.TLSRootCACertificate)
if err != nil {
return nil, err
}
rootCAPool, err = newCertPoolFromPEM(rootCrtFile)
if err != nil {
return nil, err
}
cfg.TLSInsecure = false
}
tlsConf = &tls.Config{
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: cfg.TLSInsecure, //nolint:gosec
RootCAs: rootCAPool,
}
}
opts := []natsjs.Option{
natsjs.TLSConfig(tlsConf),
natsjs.Address(cfg.Endpoint),
natsjs.ClusterID(cfg.Cluster),
natsjs.SynchronousPublish(true),
natsjs.Name(connName),
natsjs.Authenticate(cfg.AuthUsername, cfg.AuthPassword),
}
if disableDurability {
opts = append(opts, natsjs.DisableDurableStreams())
}
s, err := Nats(opts...)
if err != nil {
return nil, err
}
// apply a MaxAge to the main queue to prevent it from filling up
ctx := context.Background()
jsConn, err := raw.JetStream(ctx, connName, raw.Config{
Endpoint: cfg.Endpoint,
Cluster: cfg.Cluster,
TLSInsecure: cfg.TLSInsecure,
TLSRootCACertificate: cfg.TLSRootCACertificate,
EnableTLS: cfg.EnableTLS,
AuthUsername: cfg.AuthUsername,
AuthPassword: cfg.AuthPassword,
})
if err != nil {
return nil, err
}
streamCfg := jetstream.StreamConfig{
Name: "main-queue",
MaxAge: 7 * 24 * time.Hour,
}
_, err = jsConn.CreateStream(ctx, streamCfg)
if err != nil {
// If the stream already exists, update its configuration
if err == jetstream.ErrStreamNameAlreadyInUse {
_, _ = jsConn.UpdateStream(ctx, streamCfg)
}
}
return s, nil
}
// nats returns a nats streaming client
// retries exponentially to connect to a nats server
func Nats(opts ...natsjs.Option) (events.Stream, error) {
b := backoff.NewExponentialBackOff()
var stream events.Stream
o := func() error {
n := b.NextBackOff()
s, err := natsjs.NewStream(opts...)
if err != nil && n > time.Second {
logger.New().Error().Err(err).Msgf("can't connect to nats (jetstream) server, retrying in %s", n)
}
stream = s
return err
}
err := backoff.Retry(o, b)
return stream, err
}
// newCertPoolFromPEM reads certificates from io.Reader and returns a x509.CertPool
// containing those certificates.
func newCertPoolFromPEM(crts ...io.Reader) (*x509.CertPool, error) {
certPool := x509.NewCertPool()
var buf bytes.Buffer
for _, c := range crts {
if _, err := io.Copy(&buf, c); err != nil {
return nil, err
}
if !certPool.AppendCertsFromPEM(buf.Bytes()) {
return nil, errors.New("failed to append cert from PEM")
}
buf.Reset()
}
return certPool, nil
}
@@ -0,0 +1,42 @@
// Package stream provides streaming clients used by `Consume` and `Publish` methods
package stream
import (
"encoding/json"
"reflect"
"go-micro.dev/v4/events"
)
// Chan is a channel based streaming clients
// Useful for tests or in memory applications
type Chan [2]chan interface{}
// Publish implementation
func (ch Chan) Publish(_ string, msg interface{}, _ ...events.PublishOption) error {
go func() {
ch[0] <- msg
}()
return nil
}
// Consume implementation
func (ch Chan) Consume(_ string, _ ...events.ConsumeOption) (<-chan events.Event, error) {
evch := make(chan events.Event)
go func() {
for {
e := <-ch[1]
if e == nil {
// channel closed
return
}
b, _ := json.Marshal(e)
evname := reflect.TypeOf(e).String()
evch <- events.Event{
Payload: b,
Metadata: map[string]string{"eventtype": evname},
}
}
}()
return evch, nil
}
+59
View File
@@ -0,0 +1,59 @@
// Copyright 2018-2022 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package events
import (
"encoding/json"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
)
// TagsAdded is emitted when a Tag has been added
type TagsAdded struct {
SpaceOwner *user.UserId
Tags string
Ref *provider.Reference
Executant *user.UserId
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (TagsAdded) Unmarshal(v []byte) (interface{}, error) {
e := TagsAdded{}
err := json.Unmarshal(v, &e)
return e, err
}
// TagsRemoved is emitted when a Tag has been added
type TagsRemoved struct {
SpaceOwner *user.UserId
Tags string
Ref *provider.Reference
Executant *user.UserId
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (TagsRemoved) Unmarshal(v []byte) (interface{}, error) {
e := TagsRemoved{}
err := json.Unmarshal(v, &e)
return e, err
}
+134
View File
@@ -0,0 +1,134 @@
// Copyright 2018-2022 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package events
import (
"encoding/json"
"time"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
)
// UserCreated is emitted when a user was created
type UserCreated struct {
Executant *user.UserId
UserID string
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (UserCreated) Unmarshal(v []byte) (interface{}, error) {
e := UserCreated{}
err := json.Unmarshal(v, &e)
return e, err
}
// UserDeleted is emitted when a user was deleted
type UserDeleted struct {
Executant *user.UserId
UserID string
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (UserDeleted) Unmarshal(v []byte) (interface{}, error) {
e := UserDeleted{}
err := json.Unmarshal(v, &e)
return e, err
}
// UserSoftDeleted is emitted when a user was soft-deleted
type UserSoftDeleted struct {
Executant *user.UserId
UserID string
Timestamp *types.Timestamp
RetentionTime time.Duration
Reason string
}
// Unmarshal to fulfill unmarshaller interface
func (UserSoftDeleted) Unmarshal(v []byte) (interface{}, error) {
e := UserSoftDeleted{}
err := json.Unmarshal(v, &e)
return e, err
}
// UserFeature represents a user feature
type UserFeature struct {
Name string
Value string
OldValue *string
}
// UserFeatureChanged is emitted when a user feature was changed
type UserFeatureChanged struct {
Executant *user.UserId
UserID string
Features []UserFeature
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (UserFeatureChanged) Unmarshal(v []byte) (interface{}, error) {
e := UserFeatureChanged{}
err := json.Unmarshal(v, &e)
return e, err
}
// PersonalDataExtracted is emitted when a user data extraction is finished
type PersonalDataExtracted struct {
Executant *user.UserId
Timestamp *types.Timestamp
ErrorMsg string
}
// Unmarshal to fulfill umarshaller interface
func (PersonalDataExtracted) Unmarshal(v []byte) (interface{}, error) {
e := PersonalDataExtracted{}
err := json.Unmarshal(v, &e)
return e, err
}
// BackchannelLogout is emitted when the callback from the identity provider is received
type BackchannelLogout struct {
Executant *user.UserId
SessionId string
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (BackchannelLogout) Unmarshal(v []byte) (interface{}, error) {
e := BackchannelLogout{}
err := json.Unmarshal(v, &e)
return e, err
}
// UserSignedIn is emitted when a user signs in
type UserSignedIn struct {
Executant *user.UserId
Timestamp *types.Timestamp
}
// Unmarshal to fulfill umarshaller interface
func (UserSignedIn) Unmarshal(v []byte) (interface{}, error) {
e := UserSignedIn{}
err := json.Unmarshal(v, &e)
return e, err
}