diff --git a/api/converter/from_pb.go b/api/converter/from_pb.go index ef3d8f9ea..20e94f0ba 100644 --- a/api/converter/from_pb.go +++ b/api/converter/from_pb.go @@ -18,6 +18,7 @@ package converter import ( "fmt" + gotime "time" protoTypes "github.com/gogo/protobuf/types" @@ -69,14 +70,15 @@ func FromProject(pbProject *api.Project) (*types.Project, error) { return nil, fmt.Errorf("convert updatedAt to timestamp: %w", err) } return &types.Project{ - ID: types.ID(pbProject.Id), - Name: pbProject.Name, - AuthWebhookURL: pbProject.AuthWebhookUrl, - AuthWebhookMethods: pbProject.AuthWebhookMethods, - PublicKey: pbProject.PublicKey, - SecretKey: pbProject.SecretKey, - CreatedAt: createdAt, - UpdatedAt: updatedAt, + ID: types.ID(pbProject.Id), + Name: pbProject.Name, + AuthWebhookURL: pbProject.AuthWebhookUrl, + AuthWebhookMethods: pbProject.AuthWebhookMethods, + DeactivateThreshold: gotime.Duration(pbProject.DeactivateThreshold) * gotime.Millisecond, + PublicKey: pbProject.PublicKey, + SecretKey: pbProject.SecretKey, + CreatedAt: createdAt, + UpdatedAt: updatedAt, }, nil } @@ -663,6 +665,9 @@ func FromUpdatableProjectFields(pbProjectFields *api.UpdatableProjectFields) (*t if pbProjectFields.AuthWebhookMethods != nil { updatableProjectFields.AuthWebhookMethods = &pbProjectFields.AuthWebhookMethods.Methods } + if pbProjectFields.DeactivateThreshold != 0 { + updatableProjectFields.DeactivateThreshold = pbProjectFields.DeactivateThreshold + } return updatableProjectFields, nil } diff --git a/api/converter/to_pb.go b/api/converter/to_pb.go index 5a51c9f55..bbdcaab53 100644 --- a/api/converter/to_pb.go +++ b/api/converter/to_pb.go @@ -72,14 +72,15 @@ func ToProject(project *types.Project) (*api.Project, error) { } return &api.Project{ - Id: project.ID.String(), - Name: project.Name, - AuthWebhookUrl: project.AuthWebhookURL, - AuthWebhookMethods: project.AuthWebhookMethods, - PublicKey: project.PublicKey, - SecretKey: project.SecretKey, - CreatedAt: pbCreatedAt, - UpdatedAt: pbUpdatedAt, + Id: project.ID.String(), + Name: project.Name, + AuthWebhookUrl: project.AuthWebhookURL, + AuthWebhookMethods: project.AuthWebhookMethods, + DeactivateThreshold: project.DeactivateThreshold.Milliseconds(), + PublicKey: project.PublicKey, + SecretKey: project.SecretKey, + CreatedAt: pbCreatedAt, + UpdatedAt: pbUpdatedAt, }, nil } @@ -511,6 +512,9 @@ func ToUpdatableProjectFields(fields *types.UpdatableProjectFields) (*api.Updata pbUpdatableProjectFields.AuthWebhookMethods = &api.UpdatableProjectFields_AuthWebhookMethods{ Methods: *fields.AuthWebhookMethods, } + } + if fields.DeactivateThreshold != 0 { + pbUpdatableProjectFields.DeactivateThreshold = fields.DeactivateThreshold } else { pbUpdatableProjectFields.AuthWebhookMethods = nil } diff --git a/api/types/project.go b/api/types/project.go index 9137d7891..44a3ae0a1 100644 --- a/api/types/project.go +++ b/api/types/project.go @@ -48,6 +48,10 @@ type Project struct { // UpdatedAt is the time when the project was updated. UpdatedAt time.Time `json:"updated_at"` + + // DeactivateThreshold is the time after which clients are + // considered deactivate in specific project. + DeactivateThreshold time.Duration `bson:"deactivate_threshold"` } // RequireAuth returns whether the given method requires authorization. diff --git a/api/types/updatable_project_fields.go b/api/types/updatable_project_fields.go index 35b21953d..dbff9e1a3 100644 --- a/api/types/updatable_project_fields.go +++ b/api/types/updatable_project_fields.go @@ -36,11 +36,14 @@ type UpdatableProjectFields struct { // AuthWebhookMethods is the methods that run the authorization webhook. AuthWebhookMethods *[]string `bson:"auth_webhook_methods,omitempty" validate:"omitempty,invalid_webhook_method"` + + // DeactivateThreshold is the time after which clients are considered deactivate in specific project. + DeactivateThreshold int64 `bson:"deactivate_threshold,omitempty" validate:"omitempty"` } // Validate validates the UpdatableProjectFields. func (i *UpdatableProjectFields) Validate() error { - if i.Name == nil && i.AuthWebhookURL == nil && i.AuthWebhookMethods == nil { + if i.Name == nil && i.AuthWebhookURL == nil && i.AuthWebhookMethods == nil && i.DeactivateThreshold == 0 { return ErrEmptyProjectFields } diff --git a/api/types/updatable_project_fields_test.go b/api/types/updatable_project_fields_test.go index d3ef8f750..22376a7ab 100644 --- a/api/types/updatable_project_fields_test.go +++ b/api/types/updatable_project_fields_test.go @@ -18,6 +18,7 @@ package types_test import ( "testing" + "time" "github.com/stretchr/testify/assert" @@ -33,10 +34,12 @@ func TestUpdatableProjectFields(t *testing.T) { string(types.AttachDocument), string(types.WatchDocuments), } + newDeactivateThresholds := 1 * time.Hour fields := &types.UpdatableProjectFields{ - Name: &newName, - AuthWebhookURL: &newAuthWebhookURL, - AuthWebhookMethods: &newAuthWebhookMethods, + Name: &newName, + AuthWebhookURL: &newAuthWebhookURL, + AuthWebhookMethods: &newAuthWebhookMethods, + DeactivateThreshold: int64(newDeactivateThresholds.Milliseconds()), } assert.NoError(t, fields.Validate()) @@ -49,8 +52,9 @@ func TestUpdatableProjectFields(t *testing.T) { assert.NoError(t, fields.Validate()) fields = &types.UpdatableProjectFields{ - Name: &newName, - AuthWebhookURL: &newAuthWebhookURL, + Name: &newName, + AuthWebhookURL: &newAuthWebhookURL, + DeactivateThreshold: int64(newDeactivateThresholds.Milliseconds()), } assert.NoError(t, fields.Validate()) @@ -59,9 +63,10 @@ func TestUpdatableProjectFields(t *testing.T) { "InvalidMethods", } fields = &types.UpdatableProjectFields{ - Name: &newName, - AuthWebhookURL: &newAuthWebhookURL, - AuthWebhookMethods: &newAuthWebhookMethods, + Name: &newName, + AuthWebhookURL: &newAuthWebhookURL, + AuthWebhookMethods: &newAuthWebhookMethods, + DeactivateThreshold: int64(newDeactivateThresholds.Milliseconds()), } assert.ErrorAs(t, fields.Validate(), &invalidFieldsError) }) diff --git a/api/yorkie/v1/resources.pb.go b/api/yorkie/v1/resources.pb.go index 2001d44a0..ecb253abd 100644 --- a/api/yorkie/v1/resources.pb.go +++ b/api/yorkie/v1/resources.pb.go @@ -2023,8 +2023,9 @@ type Project struct { SecretKey string `protobuf:"bytes,4,opt,name=secret_key,json=secretKey,proto3" json:"secret_key,omitempty"` AuthWebhookUrl string `protobuf:"bytes,5,opt,name=auth_webhook_url,json=authWebhookUrl,proto3" json:"auth_webhook_url,omitempty"` AuthWebhookMethods []string `protobuf:"bytes,6,rep,name=auth_webhook_methods,json=authWebhookMethods,proto3" json:"auth_webhook_methods,omitempty"` - CreatedAt *types.Timestamp `protobuf:"bytes,7,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt *types.Timestamp `protobuf:"bytes,8,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` + DeactivateThreshold int64 `protobuf:"varint,7,opt,name=deactivate_threshold,json=deactivateThreshold,proto3" json:"deactivate_threshold,omitempty"` + CreatedAt *types.Timestamp `protobuf:"bytes,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt *types.Timestamp `protobuf:"bytes,9,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2105,6 +2106,13 @@ func (m *Project) GetAuthWebhookMethods() []string { return nil } +func (m *Project) GetDeactivateThreshold() int64 { + if m != nil { + return m.DeactivateThreshold + } + return 0 +} + func (m *Project) GetCreatedAt() *types.Timestamp { if m != nil { return m.CreatedAt @@ -2123,6 +2131,7 @@ type UpdatableProjectFields struct { Name *types.StringValue `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` AuthWebhookUrl *types.StringValue `protobuf:"bytes,2,opt,name=auth_webhook_url,json=authWebhookUrl,proto3" json:"auth_webhook_url,omitempty"` AuthWebhookMethods *UpdatableProjectFields_AuthWebhookMethods `protobuf:"bytes,3,opt,name=auth_webhook_methods,json=authWebhookMethods,proto3" json:"auth_webhook_methods,omitempty"` + DeactivateThreshold int64 `protobuf:"varint,4,opt,name=deactivate_threshold,json=deactivateThreshold,proto3" json:"deactivate_threshold,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2182,6 +2191,13 @@ func (m *UpdatableProjectFields) GetAuthWebhookMethods() *UpdatableProjectFields return nil } +func (m *UpdatableProjectFields) GetDeactivateThreshold() int64 { + if m != nil { + return m.DeactivateThreshold + } + return 0 +} + type UpdatableProjectFields_AuthWebhookMethods struct { Methods []string `protobuf:"bytes,1,rep,name=methods,proto3" json:"methods,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -2770,144 +2786,146 @@ func init() { func init() { proto.RegisterFile("yorkie/v1/resources.proto", fileDescriptor_36361b2f5d0f0896) } var fileDescriptor_36361b2f5d0f0896 = []byte{ - // 2177 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x59, 0xdf, 0x8f, 0xdb, 0x58, - 0xf5, 0x8f, 0x1d, 0xe7, 0x87, 0x4f, 0xa6, 0x9d, 0xf4, 0x4e, 0x7f, 0xa4, 0xd9, 0x76, 0x76, 0x9a, - 0x7e, 0xbf, 0x65, 0xb6, 0x85, 0x4c, 0x3b, 0xb4, 0x0b, 0x6c, 0xb5, 0x12, 0x9e, 0xc4, 0xdb, 0x4c, - 0x77, 0x9a, 0x8c, 0x9c, 0x4c, 0x97, 0x56, 0x42, 0x96, 0xc7, 0xbe, 0xed, 0x78, 0x27, 0xb1, 0xbd, - 0xb6, 0x93, 0x6d, 0x1e, 0x78, 0x41, 0xf0, 0x06, 0xef, 0xfc, 0x01, 0x48, 0x48, 0xfc, 0x07, 0xfb, - 0x80, 0x90, 0x78, 0x40, 0xbc, 0x01, 0x02, 0x89, 0x57, 0xe8, 0x3e, 0x20, 0x1e, 0x01, 0x89, 0x67, - 0x74, 0xef, 0xb5, 0x1d, 0xc7, 0x71, 0xb2, 0x69, 0xa8, 0x50, 0x97, 0x37, 0xdf, 0x7b, 0x3f, 0xe7, - 0xdc, 0xf3, 0xfb, 0x1e, 0xdf, 0x0b, 0x97, 0xc7, 0xb6, 0x7b, 0x6a, 0xe2, 0x9d, 0xd1, 0x9d, 0x1d, - 0x17, 0x7b, 0xf6, 0xd0, 0xd5, 0xb1, 0x57, 0x77, 0x5c, 0xdb, 0xb7, 0x91, 0xc8, 0x96, 0xea, 0xa3, - 0x3b, 0xd5, 0xb7, 0x9f, 0xdb, 0xf6, 0xf3, 0x3e, 0xde, 0xa1, 0x0b, 0xc7, 0xc3, 0x67, 0x3b, 0xbe, - 0x39, 0xc0, 0x9e, 0xaf, 0x0d, 0x1c, 0x86, 0xad, 0x6e, 0x26, 0x01, 0x9f, 0xba, 0x9a, 0xe3, 0x60, - 0x37, 0xe0, 0x55, 0xfb, 0x07, 0x07, 0xd0, 0x38, 0xd1, 0xac, 0xe7, 0xf8, 0x50, 0xd3, 0x4f, 0xd1, - 0x35, 0x58, 0x33, 0x6c, 0x7d, 0x38, 0xc0, 0x96, 0xaf, 0x9e, 0xe2, 0x71, 0x85, 0xdb, 0xe2, 0xb6, - 0x45, 0xa5, 0x14, 0xce, 0x7d, 0x88, 0xc7, 0xe8, 0x1e, 0x80, 0x7e, 0x82, 0xf5, 0x53, 0xc7, 0x36, - 0x2d, 0xbf, 0xc2, 0x6f, 0x71, 0xdb, 0xa5, 0xdd, 0x0b, 0xf5, 0x48, 0xa4, 0x7a, 0x23, 0x5a, 0x54, - 0x62, 0x40, 0x54, 0x85, 0xa2, 0x67, 0x69, 0x8e, 0x77, 0x62, 0xfb, 0x95, 0xec, 0x16, 0xb7, 0xbd, - 0xa6, 0x44, 0x63, 0x74, 0x0b, 0x0a, 0x3a, 0x95, 0xc1, 0xab, 0x08, 0x5b, 0xd9, 0xed, 0xd2, 0xee, - 0xb9, 0x29, 0x7e, 0x64, 0x45, 0x09, 0x11, 0x48, 0x82, 0x73, 0x03, 0xd3, 0x52, 0xbd, 0xb1, 0xa5, - 0x63, 0x43, 0xf5, 0x4d, 0xfd, 0x14, 0xfb, 0x95, 0xdc, 0x8c, 0x18, 0x3d, 0x73, 0x80, 0x7b, 0x74, - 0x51, 0x59, 0x1f, 0x98, 0x56, 0x97, 0xc2, 0xd9, 0x44, 0xed, 0x7b, 0x90, 0x67, 0x5c, 0xd1, 0x75, - 0xe0, 0x4d, 0x83, 0x6a, 0x59, 0xda, 0xdd, 0x98, 0xd9, 0x74, 0xbf, 0xa9, 0xf0, 0xa6, 0x81, 0x2a, - 0x50, 0x18, 0x60, 0xcf, 0xd3, 0x9e, 0x63, 0xaa, 0xae, 0xa8, 0x84, 0x43, 0x74, 0x17, 0xc0, 0x76, - 0xb0, 0xab, 0xf9, 0xa6, 0x6d, 0x79, 0x95, 0x2c, 0x95, 0xfd, 0x7c, 0x8c, 0x4d, 0x27, 0x5c, 0x54, - 0x62, 0xb8, 0xda, 0x0f, 0x39, 0x28, 0x86, 0x1b, 0xa0, 0xab, 0x00, 0x7a, 0xdf, 0x24, 0xf6, 0xf6, - 0xf0, 0x27, 0x54, 0x92, 0x33, 0x8a, 0xc8, 0x66, 0xba, 0xf8, 0x13, 0x74, 0x0d, 0xc0, 0xc3, 0xee, - 0x08, 0xbb, 0x74, 0x99, 0x6c, 0x9f, 0xdd, 0xe3, 0x6f, 0x73, 0x8a, 0xc8, 0x66, 0x09, 0xe4, 0x0a, - 0x14, 0xfa, 0xda, 0xc0, 0xb1, 0x5d, 0x66, 0x58, 0xb6, 0x1e, 0x4e, 0xa1, 0xcb, 0x50, 0xd4, 0x74, - 0xdf, 0x76, 0x55, 0xd3, 0xa8, 0x08, 0xd4, 0xee, 0x05, 0x3a, 0xde, 0x37, 0x6a, 0x9f, 0x9f, 0x07, - 0x31, 0x92, 0x10, 0x7d, 0x15, 0xb2, 0x1e, 0xf6, 0x03, 0x5b, 0x54, 0xd2, 0x94, 0xa8, 0x77, 0xb1, - 0xdf, 0xca, 0x28, 0x04, 0x46, 0xd0, 0x9a, 0x61, 0x04, 0xee, 0x4f, 0x47, 0x4b, 0x86, 0x41, 0xd0, - 0x9a, 0x61, 0xa0, 0x1d, 0x10, 0x06, 0xf6, 0x08, 0x53, 0xf9, 0x4a, 0xbb, 0x97, 0x53, 0xe1, 0x8f, - 0xec, 0x11, 0x6e, 0x65, 0x14, 0x0a, 0x44, 0xf7, 0x20, 0xef, 0x62, 0x4a, 0x22, 0x50, 0x92, 0xb7, - 0x52, 0x49, 0x14, 0x0a, 0x69, 0x65, 0x94, 0x00, 0x4c, 0xf6, 0xc1, 0x86, 0x19, 0x86, 0x43, 0xfa, - 0x3e, 0xb2, 0x61, 0x12, 0x2d, 0x28, 0x90, 0xec, 0xe3, 0xe1, 0x3e, 0xd6, 0xfd, 0x4a, 0x7e, 0xc1, - 0x3e, 0x5d, 0x0a, 0x21, 0xfb, 0x30, 0x30, 0xda, 0x85, 0x9c, 0xe7, 0x8f, 0xfb, 0xb8, 0x52, 0xa0, - 0x54, 0xd5, 0x74, 0x2a, 0x82, 0x68, 0x65, 0x14, 0x06, 0x45, 0xf7, 0xa1, 0x68, 0x5a, 0xba, 0x8b, - 0x35, 0x0f, 0x57, 0x8a, 0x94, 0xec, 0x6a, 0x2a, 0xd9, 0x7e, 0x00, 0x6a, 0x65, 0x94, 0x88, 0xa0, - 0xfa, 0x6b, 0x0e, 0xb2, 0x5d, 0xec, 0x93, 0xe0, 0x77, 0x34, 0x97, 0x44, 0x0b, 0x59, 0xf0, 0xb1, - 0xa1, 0x6a, 0xa1, 0xcb, 0xe6, 0x05, 0x3f, 0xc3, 0x37, 0x18, 0x5c, 0xf2, 0x51, 0x19, 0xb2, 0x24, - 0xb3, 0x59, 0x24, 0x93, 0x4f, 0xa2, 0xcd, 0x48, 0xeb, 0x0f, 0x43, 0xf7, 0x5c, 0x89, 0x31, 0x7a, - 0xd8, 0xed, 0xb4, 0xe5, 0x3e, 0x26, 0xb9, 0xdf, 0x35, 0x07, 0x4e, 0x1f, 0x2b, 0x0c, 0x8a, 0xde, - 0x85, 0x12, 0x7e, 0x81, 0xf5, 0x61, 0x20, 0x82, 0xb0, 0x48, 0x04, 0x08, 0x91, 0x92, 0x5f, 0xfd, - 0x27, 0x07, 0x59, 0xc9, 0x30, 0x5e, 0x87, 0x22, 0xef, 0xc3, 0xba, 0xe3, 0xe2, 0x51, 0x9c, 0x01, - 0xbf, 0x88, 0xc1, 0x19, 0x82, 0x9e, 0x90, 0xff, 0x37, 0xb5, 0xfe, 0x17, 0x07, 0x02, 0x89, 0xef, - 0x37, 0x40, 0xed, 0xbb, 0x00, 0x31, 0xca, 0xec, 0x22, 0x4a, 0x51, 0x8f, 0xa8, 0x56, 0x55, 0xfc, - 0x33, 0x0e, 0xf2, 0x2c, 0x4b, 0x5f, 0x87, 0xea, 0xd3, 0xb2, 0xf3, 0xab, 0xc9, 0x9e, 0x5d, 0x56, - 0xf6, 0x5f, 0x09, 0x20, 0x90, 0x62, 0xf1, 0x3a, 0x24, 0xbf, 0x09, 0xc2, 0x33, 0xd7, 0x1e, 0x04, - 0x32, 0x5f, 0x8c, 0x53, 0xe1, 0x17, 0x7e, 0xdb, 0x36, 0xf0, 0xa1, 0xed, 0x29, 0x14, 0x83, 0x6e, - 0x00, 0xef, 0xdb, 0x81, 0x98, 0xf3, 0x90, 0xbc, 0x6f, 0xa3, 0x13, 0xb8, 0x34, 0x91, 0x47, 0x1d, - 0x68, 0x8e, 0x7a, 0x3c, 0x56, 0x69, 0x6d, 0x0f, 0x4e, 0xd1, 0xdd, 0xb9, 0xf5, 0xaf, 0x1e, 0x49, - 0xf6, 0x48, 0x73, 0xf6, 0xc6, 0x12, 0x21, 0x92, 0x2d, 0xdf, 0x1d, 0x2b, 0x1b, 0xfa, 0xec, 0x0a, - 0x39, 0x00, 0x75, 0xdb, 0xf2, 0xb1, 0xc5, 0x2a, 0xab, 0xa8, 0x84, 0xc3, 0xa4, 0x6d, 0xf3, 0x4b, - 0xda, 0x16, 0xed, 0x03, 0x68, 0xbe, 0xef, 0x9a, 0xc7, 0x43, 0x1f, 0x7b, 0x95, 0x02, 0x15, 0xf7, - 0x9d, 0xf9, 0xe2, 0x4a, 0x11, 0x96, 0x49, 0x19, 0x23, 0xae, 0x7e, 0x17, 0x2a, 0xf3, 0xb4, 0x09, - 0x6b, 0x1d, 0x37, 0xa9, 0x75, 0xb7, 0xc2, 0xac, 0x5f, 0x18, 0x3d, 0x0c, 0xf3, 0x1e, 0xff, 0x4d, - 0xae, 0xfa, 0x3e, 0xac, 0x27, 0x76, 0x4f, 0xe1, 0x7a, 0x3e, 0xce, 0x55, 0x8c, 0x93, 0xff, 0x89, - 0x83, 0x3c, 0x3b, 0x3e, 0xde, 0xd4, 0x30, 0x5a, 0x35, 0xb5, 0xff, 0xc2, 0x43, 0x8e, 0x1e, 0x71, - 0x6f, 0xaa, 0x62, 0x0f, 0xa7, 0x62, 0x8c, 0xa5, 0xc4, 0xcd, 0xf9, 0x27, 0xf5, 0xa2, 0x20, 0x4b, - 0x1a, 0x29, 0xb7, 0xac, 0x91, 0xfe, 0xc3, 0xe8, 0xf9, 0x8c, 0x83, 0x62, 0xd8, 0x0f, 0xbc, 0x0e, - 0x33, 0xef, 0x4e, 0x47, 0xff, 0x2a, 0x67, 0xde, 0xb2, 0xe5, 0x73, 0x2f, 0x0f, 0xc2, 0xb1, 0x6d, - 0x8c, 0x6b, 0x7f, 0xe7, 0xe0, 0xdc, 0x0c, 0xf3, 0x44, 0x29, 0xe7, 0x96, 0x2c, 0xe5, 0xb7, 0xa1, - 0x48, 0xce, 0x92, 0x2f, 0x2e, 0xff, 0x05, 0x0a, 0x63, 0x47, 0x06, 0xeb, 0x0d, 0x97, 0x38, 0xee, - 0x02, 0xa0, 0xe4, 0xa3, 0x6d, 0x10, 0xfc, 0xb1, 0xc3, 0x9a, 0xcf, 0xb3, 0x53, 0x1d, 0xfd, 0x63, - 0x62, 0x93, 0xde, 0xd8, 0xc1, 0x0a, 0x45, 0x4c, 0x7c, 0x97, 0xa3, 0xbd, 0x35, 0x1b, 0xd4, 0x7e, - 0x5a, 0x82, 0x52, 0x4c, 0x67, 0xd4, 0x84, 0xd2, 0xc7, 0x9e, 0x6d, 0xa9, 0xf6, 0xf1, 0xc7, 0xa4, - 0xd7, 0x64, 0xea, 0x5e, 0x4b, 0xb7, 0x3e, 0xfd, 0xee, 0x50, 0x60, 0x2b, 0xa3, 0x00, 0xa1, 0x63, - 0x23, 0x24, 0x01, 0x1d, 0xa9, 0x9a, 0xeb, 0x6a, 0xe3, 0x40, 0xff, 0xad, 0x05, 0x4c, 0x24, 0x82, - 0x6b, 0x65, 0x14, 0x91, 0x50, 0xd1, 0x01, 0xfa, 0x36, 0x88, 0x8e, 0x6b, 0x0e, 0x4c, 0xdf, 0x8c, - 0xba, 0xf1, 0x79, 0x1c, 0x0e, 0x43, 0x1c, 0xe1, 0x10, 0x11, 0xa1, 0x3b, 0x20, 0xf8, 0xf8, 0x45, - 0x98, 0x02, 0x6f, 0xcd, 0x21, 0x26, 0xb9, 0x48, 0x9a, 0x6c, 0x02, 0x45, 0xef, 0x91, 0xe3, 0x63, - 0x68, 0xf9, 0xd8, 0x0d, 0x0e, 0x88, 0xcd, 0x39, 0x54, 0x0d, 0x86, 0x6a, 0x65, 0x94, 0x90, 0xa0, - 0xfa, 0x47, 0x0e, 0x60, 0x62, 0x10, 0xb4, 0x0d, 0x39, 0xcb, 0x36, 0xb0, 0x57, 0xe1, 0x68, 0x3a, - 0xa3, 0x18, 0x23, 0xa5, 0xd5, 0x23, 0xd9, 0xaf, 0x30, 0xc0, 0x8a, 0xbd, 0x42, 0x3c, 0xc0, 0xb2, - 0x2b, 0x04, 0x98, 0xb0, 0x5c, 0x80, 0x55, 0xff, 0xc0, 0x81, 0x18, 0xb9, 0x68, 0xa1, 0x56, 0x0f, - 0xa4, 0x2f, 0x8f, 0x56, 0x7f, 0xe3, 0x40, 0x8c, 0xc2, 0x26, 0x4a, 0x22, 0x6e, 0xf9, 0x24, 0xe2, - 0x63, 0x49, 0xb4, 0x62, 0xa7, 0x1a, 0xd7, 0x55, 0x58, 0x41, 0xd7, 0xdc, 0x92, 0xba, 0xfe, 0x96, - 0x03, 0x81, 0x44, 0x39, 0x7a, 0x67, 0xda, 0x79, 0x1b, 0x29, 0x27, 0xd2, 0x97, 0xc3, 0x7b, 0x7f, - 0xe5, 0xa0, 0x10, 0x64, 0xe0, 0xff, 0xb6, 0xef, 0xa2, 0xa3, 0xe9, 0x11, 0x14, 0x82, 0xaa, 0x91, - 0x72, 0x2a, 0xdf, 0x86, 0x02, 0x66, 0x75, 0x29, 0xa5, 0x2b, 0x89, 0x55, 0x2d, 0x25, 0x84, 0xd5, - 0x74, 0x28, 0x04, 0xe9, 0x8a, 0x6e, 0x80, 0x60, 0x91, 0x2a, 0xc9, 0x2a, 0x7d, 0x5a, 0x42, 0xd3, - 0xf5, 0x15, 0x36, 0x79, 0x0a, 0x6b, 0x61, 0x58, 0x91, 0xce, 0x62, 0x62, 0x7f, 0x2e, 0xd6, 0x3c, - 0x10, 0xbb, 0x0c, 0x1d, 0x63, 0xb9, 0x48, 0x0b, 0x80, 0x92, 0x5f, 0xfb, 0x3d, 0x0f, 0xc5, 0x90, - 0x39, 0xfa, 0xff, 0xd8, 0xd5, 0xd8, 0x85, 0x94, 0xa0, 0x0e, 0x2e, 0xc7, 0x52, 0x9b, 0x97, 0x15, - 0x8f, 0xdd, 0x7b, 0x50, 0x32, 0x2d, 0x4f, 0xa5, 0xbf, 0xb7, 0xc1, 0x75, 0xd5, 0xdc, 0xbd, 0x45, - 0xd3, 0xf2, 0x0e, 0x5d, 0x3c, 0xda, 0x37, 0x50, 0x63, 0xaa, 0xd1, 0xcb, 0xd1, 0x34, 0xbc, 0x9e, - 0x42, 0xb5, 0xf0, 0x37, 0xe2, 0xf1, 0x32, 0x9d, 0xda, 0xd7, 0xa6, 0xfb, 0xa7, 0x4b, 0x29, 0x9b, - 0x10, 0x26, 0xb1, 0x16, 0xae, 0xf6, 0x14, 0x60, 0x22, 0xf5, 0x8a, 0x6d, 0xcf, 0x45, 0xc8, 0xdb, - 0xcf, 0x9e, 0x79, 0x98, 0x79, 0x32, 0xa7, 0x04, 0xa3, 0xda, 0x00, 0x84, 0x23, 0x0f, 0xbb, 0xe8, - 0x6c, 0xe4, 0x2a, 0x91, 0xfa, 0xa4, 0x0a, 0xc5, 0xa1, 0x87, 0x5d, 0x4b, 0x1b, 0x84, 0x6e, 0x89, - 0xc6, 0xe8, 0x5b, 0x29, 0x99, 0x59, 0xad, 0xb3, 0x5b, 0xe2, 0x7a, 0x78, 0x4b, 0x4c, 0xe5, 0xa0, - 0xd7, 0xc8, 0x31, 0x31, 0x6a, 0xbf, 0xe0, 0xa1, 0x70, 0xe8, 0xda, 0xf4, 0x20, 0x4e, 0x6e, 0x89, - 0x40, 0x88, 0x6d, 0x47, 0xbf, 0xd1, 0x55, 0x00, 0x67, 0x78, 0xdc, 0x37, 0x75, 0x7a, 0x95, 0x9c, - 0xa5, 0x2b, 0x22, 0x9b, 0xf9, 0x10, 0x8f, 0xc9, 0xb2, 0x87, 0x75, 0x17, 0xb3, 0x9b, 0x66, 0x81, - 0x2d, 0xb3, 0x19, 0xb2, 0xbc, 0x0d, 0x65, 0x6d, 0xe8, 0x9f, 0xa8, 0x9f, 0xe2, 0xe3, 0x13, 0xdb, - 0x3e, 0x55, 0x87, 0x6e, 0x3f, 0xf8, 0xfb, 0x3c, 0x4b, 0xe6, 0x3f, 0x62, 0xd3, 0x47, 0x6e, 0x1f, - 0xdd, 0x86, 0xf3, 0x53, 0xc8, 0x01, 0xf6, 0x4f, 0x6c, 0xc3, 0xab, 0xe4, 0xb7, 0xb2, 0xdb, 0xa2, - 0x82, 0x62, 0xe8, 0x47, 0x6c, 0x25, 0x61, 0x84, 0xc2, 0x2b, 0x18, 0x81, 0x90, 0xc6, 0x32, 0xab, - 0xf8, 0xc5, 0xa4, 0x93, 0xf4, 0xfa, 0x39, 0x0f, 0x17, 0x8f, 0xc8, 0x48, 0x3b, 0xee, 0xe3, 0xc0, - 0x90, 0x1f, 0x98, 0xb8, 0x6f, 0x78, 0xe8, 0x76, 0x60, 0x3e, 0x2e, 0xe8, 0xcb, 0x93, 0xfc, 0xba, - 0xbe, 0x6b, 0x5a, 0xcf, 0x69, 0xed, 0x0d, 0x8c, 0xfb, 0x41, 0x8a, 0x79, 0xf8, 0x25, 0xa8, 0x93, - 0xc6, 0x7b, 0x36, 0xc7, 0x78, 0x2c, 0x32, 0xee, 0xc6, 0x62, 0x33, 0x5d, 0xf4, 0xba, 0x34, 0x63, - 0xde, 0x34, 0x93, 0x57, 0xeb, 0x80, 0x66, 0x91, 0xec, 0x6a, 0x9d, 0x6d, 0xc8, 0x51, 0x6f, 0x85, - 0xc3, 0xda, 0xf7, 0x79, 0x58, 0x6f, 0x06, 0xcf, 0x0e, 0xdd, 0xe1, 0x60, 0xa0, 0xb9, 0xe3, 0x99, - 0xa0, 0x9b, 0xbd, 0xca, 0x4c, 0xbe, 0x32, 0x88, 0xb1, 0x57, 0x86, 0x69, 0xa7, 0x0b, 0xaf, 0xe2, - 0xf4, 0xfb, 0x50, 0xd2, 0x74, 0x1d, 0x7b, 0x5e, 0xfc, 0x9c, 0x59, 0x44, 0x0b, 0x21, 0x7c, 0x26, - 0x62, 0xf2, 0xaf, 0x12, 0x31, 0x3f, 0xe2, 0xa0, 0x78, 0xe8, 0x62, 0x0f, 0x5b, 0x3a, 0x3d, 0x69, - 0xf5, 0xbe, 0xad, 0x9f, 0x52, 0x03, 0xe4, 0x14, 0x36, 0x20, 0xfd, 0x38, 0x71, 0x4b, 0x85, 0xa7, - 0x65, 0x2f, 0x7e, 0xa5, 0x1c, 0x12, 0xd6, 0x9b, 0x9a, 0xaf, 0xb1, 0x82, 0x47, 0xa1, 0xd5, 0x6f, - 0x80, 0x18, 0x4d, 0xbd, 0xca, 0xef, 0x68, 0x6d, 0x1f, 0xf2, 0x0d, 0xfa, 0x32, 0x11, 0xf3, 0xc4, - 0x1a, 0xf5, 0xc4, 0x0e, 0x14, 0x9d, 0x60, 0xbb, 0x20, 0x0a, 0x37, 0x52, 0x24, 0x51, 0x22, 0x50, - 0xed, 0x5d, 0x28, 0x30, 0x56, 0x1e, 0x7d, 0xfd, 0x61, 0x9f, 0x41, 0x0b, 0x35, 0xf5, 0xfa, 0x43, - 0x57, 0x94, 0x10, 0x51, 0x6b, 0x03, 0x4c, 0x1e, 0x98, 0x12, 0xaf, 0x23, 0x5c, 0xda, 0xeb, 0xc8, - 0xf4, 0xfb, 0x0a, 0x9f, 0x78, 0x5f, 0xa9, 0xfd, 0x80, 0x83, 0x52, 0xec, 0xe2, 0xe0, 0xf5, 0x16, - 0x68, 0xf4, 0x15, 0x58, 0x77, 0x71, 0x5f, 0x23, 0xed, 0xb0, 0x1a, 0x00, 0xb2, 0x14, 0x70, 0x36, - 0x9c, 0xee, 0xb0, 0x4a, 0xae, 0x03, 0x4c, 0x38, 0xc7, 0x5f, 0x74, 0xb8, 0xd9, 0x17, 0x9d, 0x2b, - 0x20, 0x1a, 0xb8, 0x4f, 0xba, 0x6c, 0xec, 0x86, 0x0a, 0x45, 0x13, 0x53, 0xef, 0x3d, 0xd9, 0xe9, - 0xf7, 0x9e, 0x1f, 0x73, 0x50, 0x6c, 0xda, 0xba, 0x3c, 0x22, 0x1e, 0xbc, 0x35, 0xd5, 0xe1, 0xc5, - 0x4f, 0xb2, 0x10, 0x12, 0x6b, 0xf2, 0x76, 0x80, 0xd5, 0x6d, 0xef, 0x24, 0xd8, 0x32, 0xd5, 0x49, - 0x13, 0x0c, 0xba, 0x0e, 0x67, 0xe2, 0xef, 0x88, 0xec, 0x6d, 0x4c, 0x54, 0xd6, 0x62, 0x0f, 0x89, - 0xde, 0xcd, 0x5f, 0xf2, 0x20, 0x46, 0xed, 0x24, 0xda, 0x80, 0xf5, 0xc7, 0xd2, 0xc1, 0x91, 0xac, - 0xf6, 0x9e, 0x1c, 0xca, 0x6a, 0xfb, 0xe8, 0xe0, 0xa0, 0x9c, 0x41, 0x17, 0x01, 0xc5, 0x26, 0xf7, - 0x3a, 0x9d, 0x03, 0x59, 0x6a, 0x97, 0xb9, 0xc4, 0xfc, 0x7e, 0xbb, 0x27, 0x3f, 0x90, 0x95, 0x32, - 0x9f, 0x60, 0x72, 0xd0, 0x69, 0x3f, 0x28, 0x67, 0xd1, 0x05, 0x38, 0x17, 0x9b, 0x6c, 0x76, 0x8e, - 0xf6, 0x0e, 0xe4, 0xb2, 0x90, 0x98, 0xee, 0xf6, 0x94, 0xfd, 0xf6, 0x83, 0x72, 0x0e, 0x9d, 0x87, - 0x72, 0x7c, 0xcb, 0x27, 0x3d, 0xb9, 0x5b, 0xce, 0x27, 0x18, 0x37, 0xa5, 0x9e, 0x5c, 0x2e, 0xa0, - 0x2a, 0x5c, 0x8c, 0x4d, 0x92, 0x76, 0x4d, 0xed, 0xec, 0x3d, 0x94, 0x1b, 0xbd, 0x72, 0x11, 0x5d, - 0x86, 0x0b, 0xc9, 0x35, 0x49, 0x51, 0xa4, 0x27, 0x65, 0x31, 0xc1, 0xab, 0x27, 0x7f, 0xa7, 0x57, - 0x86, 0x04, 0xaf, 0x40, 0x23, 0xb5, 0xd1, 0xee, 0x95, 0x4b, 0xe8, 0x12, 0x6c, 0x24, 0xb4, 0xa2, - 0x0b, 0x6b, 0x37, 0x7f, 0xc6, 0xc1, 0x5a, 0xdc, 0x5d, 0xe8, 0xff, 0x60, 0xab, 0xd9, 0x69, 0xa8, - 0xf2, 0x63, 0xb9, 0xdd, 0x0b, 0xd5, 0x6d, 0x1c, 0x3d, 0x92, 0xdb, 0xbd, 0xae, 0xda, 0x68, 0x49, - 0xed, 0x07, 0x72, 0xb3, 0x9c, 0x59, 0x88, 0xfa, 0x48, 0xea, 0x35, 0x5a, 0x72, 0xb3, 0xcc, 0xa1, - 0x1b, 0x50, 0x9b, 0x8b, 0x3a, 0x6a, 0x87, 0x38, 0x1e, 0x5d, 0x87, 0xb7, 0x13, 0xb8, 0x43, 0x45, - 0xee, 0xca, 0xed, 0x86, 0x1c, 0x6d, 0x99, 0xdd, 0xbb, 0xf5, 0x9b, 0x97, 0x9b, 0xdc, 0xef, 0x5e, - 0x6e, 0x72, 0x7f, 0x7e, 0xb9, 0xc9, 0xfd, 0xe4, 0xf3, 0xcd, 0x0c, 0x9c, 0x33, 0xf0, 0x28, 0x8c, - 0x21, 0xcd, 0x31, 0xeb, 0xa3, 0x3b, 0x87, 0xdc, 0x53, 0xa1, 0x7e, 0x7f, 0x74, 0xe7, 0x38, 0x4f, - 0xab, 0xe2, 0xd7, 0xff, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x1a, 0xf5, 0xec, 0x18, 0x04, 0x1f, 0x00, - 0x00, + // 2211 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x59, 0xcf, 0x6f, 0xdb, 0xc8, + 0xf5, 0x17, 0x29, 0xea, 0x07, 0x9f, 0x9c, 0x58, 0x19, 0x3b, 0x89, 0xa2, 0x4d, 0xbc, 0x8e, 0xf2, + 0xfd, 0xa6, 0xde, 0xa4, 0x95, 0x63, 0x37, 0xd9, 0xb6, 0x1b, 0x2c, 0x50, 0x5a, 0xe6, 0x46, 0xce, + 0x3a, 0xb2, 0x41, 0xc9, 0xd9, 0x26, 0x40, 0x41, 0xd0, 0xe4, 0x24, 0xe2, 0x5a, 0x22, 0xb9, 0x24, + 0xa5, 0x8d, 0x0e, 0xbd, 0x14, 0xed, 0xad, 0xbd, 0xf7, 0x0f, 0x28, 0xd0, 0xbf, 0x61, 0x4f, 0x05, + 0x7a, 0x28, 0x7a, 0x6b, 0x8b, 0x16, 0xe8, 0xa9, 0x40, 0x9b, 0x3d, 0x14, 0xbd, 0xf5, 0x07, 0xd0, + 0x73, 0x31, 0x33, 0x24, 0x45, 0x51, 0x94, 0x56, 0x51, 0x83, 0x22, 0xdb, 0x1b, 0x67, 0xde, 0xe7, + 0xbd, 0x79, 0xbf, 0x66, 0xde, 0xe3, 0x0c, 0x5c, 0x19, 0xd9, 0xee, 0x99, 0x89, 0xb7, 0x87, 0x3b, + 0xdb, 0x2e, 0xf6, 0xec, 0x81, 0xab, 0x63, 0xaf, 0xee, 0xb8, 0xb6, 0x6f, 0x23, 0x91, 0x91, 0xea, + 0xc3, 0x9d, 0xea, 0xdb, 0xcf, 0x6d, 0xfb, 0x79, 0x0f, 0x6f, 0x53, 0xc2, 0xe9, 0xe0, 0xd9, 0xb6, + 0x6f, 0xf6, 0xb1, 0xe7, 0x6b, 0x7d, 0x87, 0x61, 0xab, 0x1b, 0x49, 0xc0, 0xa7, 0xae, 0xe6, 0x38, + 0xd8, 0x0d, 0x64, 0xd5, 0xfe, 0xc1, 0x01, 0x34, 0xba, 0x9a, 0xf5, 0x1c, 0x1f, 0x6b, 0xfa, 0x19, + 0xba, 0x0e, 0x2b, 0x86, 0xad, 0x0f, 0xfa, 0xd8, 0xf2, 0xd5, 0x33, 0x3c, 0xaa, 0x70, 0x9b, 0xdc, + 0x96, 0xa8, 0x94, 0xc2, 0xb9, 0x0f, 0xf1, 0x08, 0xdd, 0x03, 0xd0, 0xbb, 0x58, 0x3f, 0x73, 0x6c, + 0xd3, 0xf2, 0x2b, 0xfc, 0x26, 0xb7, 0x55, 0xda, 0xbd, 0x58, 0x8f, 0x54, 0xaa, 0x37, 0x22, 0xa2, + 0x12, 0x03, 0xa2, 0x2a, 0x14, 0x3d, 0x4b, 0x73, 0xbc, 0xae, 0xed, 0x57, 0xb2, 0x9b, 0xdc, 0xd6, + 0x8a, 0x12, 0x8d, 0xd1, 0x6d, 0x28, 0xe8, 0x54, 0x07, 0xaf, 0x22, 0x6c, 0x66, 0xb7, 0x4a, 0xbb, + 0x17, 0x26, 0xe4, 0x11, 0x8a, 0x12, 0x22, 0x90, 0x04, 0x17, 0xfa, 0xa6, 0xa5, 0x7a, 0x23, 0x4b, + 0xc7, 0x86, 0xea, 0x9b, 0xfa, 0x19, 0xf6, 0x2b, 0xb9, 0x29, 0x35, 0x3a, 0x66, 0x1f, 0x77, 0x28, + 0x51, 0x59, 0xed, 0x9b, 0x56, 0x9b, 0xc2, 0xd9, 0x44, 0xed, 0x7b, 0x90, 0x67, 0x52, 0xd1, 0x0d, + 0xe0, 0x4d, 0x83, 0x5a, 0x59, 0xda, 0x5d, 0x9b, 0x5a, 0xf4, 0x60, 0x5f, 0xe1, 0x4d, 0x03, 0x55, + 0xa0, 0xd0, 0xc7, 0x9e, 0xa7, 0x3d, 0xc7, 0xd4, 0x5c, 0x51, 0x09, 0x87, 0xe8, 0x2e, 0x80, 0xed, + 0x60, 0x57, 0xf3, 0x4d, 0xdb, 0xf2, 0x2a, 0x59, 0xaa, 0xfb, 0x7a, 0x4c, 0xcc, 0x51, 0x48, 0x54, + 0x62, 0xb8, 0xda, 0x0f, 0x39, 0x28, 0x86, 0x0b, 0xa0, 0x6b, 0x00, 0x7a, 0xcf, 0x24, 0xfe, 0xf6, + 0xf0, 0x27, 0x54, 0x93, 0x73, 0x8a, 0xc8, 0x66, 0xda, 0xf8, 0x13, 0x74, 0x1d, 0xc0, 0xc3, 0xee, + 0x10, 0xbb, 0x94, 0x4c, 0x96, 0xcf, 0xee, 0xf1, 0x77, 0x38, 0x45, 0x64, 0xb3, 0x04, 0x72, 0x15, + 0x0a, 0x3d, 0xad, 0xef, 0xd8, 0x2e, 0x73, 0x2c, 0xa3, 0x87, 0x53, 0xe8, 0x0a, 0x14, 0x35, 0xdd, + 0xb7, 0x5d, 0xd5, 0x34, 0x2a, 0x02, 0xf5, 0x7b, 0x81, 0x8e, 0x0f, 0x8c, 0xda, 0xe7, 0xeb, 0x20, + 0x46, 0x1a, 0xa2, 0xaf, 0x42, 0xd6, 0xc3, 0x7e, 0xe0, 0x8b, 0x4a, 0x9a, 0x11, 0xf5, 0x36, 0xf6, + 0x9b, 0x19, 0x85, 0xc0, 0x08, 0x5a, 0x33, 0x8c, 0x20, 0xfc, 0xe9, 0x68, 0xc9, 0x30, 0x08, 0x5a, + 0x33, 0x0c, 0xb4, 0x0d, 0x42, 0xdf, 0x1e, 0x62, 0xaa, 0x5f, 0x69, 0xf7, 0x4a, 0x2a, 0xfc, 0x91, + 0x3d, 0xc4, 0xcd, 0x8c, 0x42, 0x81, 0xe8, 0x1e, 0xe4, 0x5d, 0x4c, 0x59, 0x04, 0xca, 0xf2, 0x56, + 0x2a, 0x8b, 0x42, 0x21, 0xcd, 0x8c, 0x12, 0x80, 0xc9, 0x3a, 0xd8, 0x30, 0xc3, 0x74, 0x48, 0x5f, + 0x47, 0x36, 0x4c, 0x62, 0x05, 0x05, 0x92, 0x75, 0x3c, 0xdc, 0xc3, 0xba, 0x5f, 0xc9, 0xcf, 0x59, + 0xa7, 0x4d, 0x21, 0x64, 0x1d, 0x06, 0x46, 0xbb, 0x90, 0xf3, 0xfc, 0x51, 0x0f, 0x57, 0x0a, 0x94, + 0xab, 0x9a, 0xce, 0x45, 0x10, 0xcd, 0x8c, 0xc2, 0xa0, 0xe8, 0x3e, 0x14, 0x4d, 0x4b, 0x77, 0xb1, + 0xe6, 0xe1, 0x4a, 0x91, 0xb2, 0x5d, 0x4b, 0x65, 0x3b, 0x08, 0x40, 0xcd, 0x8c, 0x12, 0x31, 0x54, + 0x7f, 0xc9, 0x41, 0xb6, 0x8d, 0x7d, 0x92, 0xfc, 0x8e, 0xe6, 0x92, 0x6c, 0x21, 0x04, 0x1f, 0x1b, + 0xaa, 0x16, 0x86, 0x6c, 0x56, 0xf2, 0x33, 0x7c, 0x83, 0xc1, 0x25, 0x1f, 0x95, 0x21, 0x4b, 0x76, + 0x36, 0xcb, 0x64, 0xf2, 0x49, 0xac, 0x19, 0x6a, 0xbd, 0x41, 0x18, 0x9e, 0xab, 0x31, 0x41, 0x0f, + 0xdb, 0x47, 0x2d, 0xb9, 0x87, 0xc9, 0xde, 0x6f, 0x9b, 0x7d, 0xa7, 0x87, 0x15, 0x06, 0x45, 0xef, + 0x42, 0x09, 0xbf, 0xc0, 0xfa, 0x20, 0x50, 0x41, 0x98, 0xa7, 0x02, 0x84, 0x48, 0xc9, 0xaf, 0xfe, + 0x93, 0x83, 0xac, 0x64, 0x18, 0xaf, 0xc3, 0x90, 0xf7, 0x61, 0xd5, 0x71, 0xf1, 0x30, 0x2e, 0x80, + 0x9f, 0x27, 0xe0, 0x1c, 0x41, 0x8f, 0xd9, 0xff, 0x9b, 0x56, 0xff, 0x8b, 0x03, 0x81, 0xe4, 0xf7, + 0x1b, 0x60, 0xf6, 0x5d, 0x80, 0x18, 0x67, 0x76, 0x1e, 0xa7, 0xa8, 0x47, 0x5c, 0xcb, 0x1a, 0xfe, + 0x19, 0x07, 0x79, 0xb6, 0x4b, 0x5f, 0x87, 0xe9, 0x93, 0xba, 0xf3, 0xcb, 0xe9, 0x9e, 0x5d, 0x54, + 0xf7, 0x5f, 0x08, 0x20, 0x90, 0xc3, 0xe2, 0x75, 0x68, 0x7e, 0x0b, 0x84, 0x67, 0xae, 0xdd, 0x0f, + 0x74, 0xbe, 0x14, 0xe7, 0xc2, 0x2f, 0xfc, 0x96, 0x6d, 0xe0, 0x63, 0xdb, 0x53, 0x28, 0x06, 0xdd, + 0x04, 0xde, 0xb7, 0x03, 0x35, 0x67, 0x21, 0x79, 0xdf, 0x46, 0x5d, 0xb8, 0x3c, 0xd6, 0x47, 0xed, + 0x6b, 0x8e, 0x7a, 0x3a, 0x52, 0xe9, 0xd9, 0x1e, 0x54, 0xd1, 0xdd, 0x99, 0xe7, 0x5f, 0x3d, 0xd2, + 0xec, 0x91, 0xe6, 0xec, 0x8d, 0x24, 0xc2, 0x24, 0x5b, 0xbe, 0x3b, 0x52, 0xd6, 0xf4, 0x69, 0x0a, + 0x29, 0x80, 0xba, 0x6d, 0xf9, 0xd8, 0x62, 0x27, 0xab, 0xa8, 0x84, 0xc3, 0xa4, 0x6f, 0xf3, 0x0b, + 0xfa, 0x16, 0x1d, 0x00, 0x68, 0xbe, 0xef, 0x9a, 0xa7, 0x03, 0x1f, 0x7b, 0x95, 0x02, 0x55, 0xf7, + 0x9d, 0xd9, 0xea, 0x4a, 0x11, 0x96, 0x69, 0x19, 0x63, 0xae, 0x7e, 0x17, 0x2a, 0xb3, 0xac, 0x09, + 0xcf, 0x3a, 0x6e, 0x7c, 0xd6, 0xdd, 0x0e, 0x77, 0xfd, 0xdc, 0xec, 0x61, 0x98, 0xf7, 0xf8, 0x6f, + 0x72, 0xd5, 0xf7, 0x61, 0x35, 0xb1, 0x7a, 0x8a, 0xd4, 0xf5, 0xb8, 0x54, 0x31, 0xce, 0xfe, 0x07, + 0x0e, 0xf2, 0xac, 0x7c, 0xbc, 0xa9, 0x69, 0xb4, 0xec, 0xd6, 0xfe, 0x33, 0x0f, 0x39, 0x5a, 0xe2, + 0xde, 0x54, 0xc3, 0x1e, 0x4e, 0xe4, 0x18, 0xdb, 0x12, 0xb7, 0x66, 0x57, 0xea, 0x79, 0x49, 0x96, + 0x74, 0x52, 0x6e, 0x51, 0x27, 0xfd, 0x87, 0xd9, 0xf3, 0x19, 0x07, 0xc5, 0xb0, 0x1f, 0x78, 0x1d, + 0x6e, 0xde, 0x9d, 0xcc, 0xfe, 0x65, 0x6a, 0xde, 0xa2, 0xc7, 0xe7, 0x5e, 0x1e, 0x84, 0x53, 0xdb, + 0x18, 0xd5, 0xfe, 0xce, 0xc1, 0x85, 0x29, 0xe1, 0x89, 0xa3, 0x9c, 0x5b, 0xf0, 0x28, 0xbf, 0x03, + 0x45, 0x52, 0x4b, 0xbe, 0xf8, 0xf8, 0x2f, 0x50, 0x18, 0x2b, 0x19, 0xac, 0x37, 0x5c, 0xa0, 0xdc, + 0x05, 0x40, 0xc9, 0x47, 0x5b, 0x20, 0xf8, 0x23, 0x87, 0x35, 0x9f, 0xe7, 0x27, 0x3a, 0xfa, 0xc7, + 0xc4, 0x27, 0x9d, 0x91, 0x83, 0x15, 0x8a, 0x18, 0xc7, 0x2e, 0x47, 0x7b, 0x6b, 0x36, 0xa8, 0xfd, + 0xb4, 0x04, 0xa5, 0x98, 0xcd, 0x68, 0x1f, 0x4a, 0x1f, 0x7b, 0xb6, 0xa5, 0xda, 0xa7, 0x1f, 0x93, + 0x5e, 0x93, 0x99, 0x7b, 0x3d, 0xdd, 0xfb, 0xf4, 0xfb, 0x88, 0x02, 0x9b, 0x19, 0x05, 0x08, 0x1f, + 0x1b, 0x21, 0x09, 0xe8, 0x48, 0xd5, 0x5c, 0x57, 0x1b, 0x05, 0xf6, 0x6f, 0xce, 0x11, 0x22, 0x11, + 0x5c, 0x33, 0xa3, 0x88, 0x84, 0x8b, 0x0e, 0xd0, 0xb7, 0x41, 0x74, 0x5c, 0xb3, 0x6f, 0xfa, 0x66, + 0xd4, 0x8d, 0xcf, 0x92, 0x70, 0x1c, 0xe2, 0x88, 0x84, 0x88, 0x09, 0xed, 0x80, 0xe0, 0xe3, 0x17, + 0xe1, 0x16, 0x78, 0x6b, 0x06, 0x33, 0xd9, 0x8b, 0xa4, 0xc9, 0x26, 0x50, 0xf4, 0x1e, 0x29, 0x1f, + 0x03, 0xcb, 0xc7, 0x6e, 0x50, 0x20, 0x36, 0x66, 0x70, 0x35, 0x18, 0xaa, 0x99, 0x51, 0x42, 0x86, + 0xea, 0xef, 0x39, 0x80, 0xb1, 0x43, 0xd0, 0x16, 0xe4, 0x2c, 0xdb, 0xc0, 0x5e, 0x85, 0xa3, 0xdb, + 0x19, 0xc5, 0x04, 0x29, 0xcd, 0x0e, 0xd9, 0xfd, 0x0a, 0x03, 0x2c, 0xd9, 0x2b, 0xc4, 0x13, 0x2c, + 0xbb, 0x44, 0x82, 0x09, 0x8b, 0x25, 0x58, 0xf5, 0x77, 0x1c, 0x88, 0x51, 0x88, 0xe6, 0x5a, 0xf5, + 0x40, 0xfa, 0xf2, 0x58, 0xf5, 0x57, 0x0e, 0xc4, 0x28, 0x6d, 0xa2, 0x4d, 0xc4, 0x2d, 0xbe, 0x89, + 0xf8, 0xd8, 0x26, 0x5a, 0xb2, 0x53, 0x8d, 0xdb, 0x2a, 0x2c, 0x61, 0x6b, 0x6e, 0x41, 0x5b, 0x7f, + 0xcd, 0x81, 0x40, 0xb2, 0x1c, 0xbd, 0x33, 0x19, 0xbc, 0xb5, 0x94, 0x8a, 0xf4, 0xe5, 0x88, 0xde, + 0x5f, 0x38, 0x28, 0x04, 0x3b, 0xf0, 0x7f, 0x3b, 0x76, 0x51, 0x69, 0x7a, 0x04, 0x85, 0xe0, 0xd4, + 0x48, 0xa9, 0xca, 0x77, 0xa0, 0x80, 0xd9, 0xb9, 0x94, 0xd2, 0x95, 0xc4, 0x4e, 0x2d, 0x25, 0x84, + 0xd5, 0x74, 0x28, 0x04, 0xdb, 0x15, 0xdd, 0x04, 0xc1, 0x22, 0xa7, 0x24, 0x3b, 0xe9, 0xd3, 0x36, + 0x34, 0xa5, 0x2f, 0xb1, 0xc8, 0x53, 0x58, 0x09, 0xd3, 0x8a, 0x74, 0x16, 0x63, 0xff, 0x73, 0xb1, + 0xe6, 0x81, 0xf8, 0x65, 0xe0, 0x18, 0x8b, 0x65, 0x5a, 0x00, 0x94, 0xfc, 0xda, 0x6f, 0x79, 0x28, + 0x86, 0xc2, 0xd1, 0xff, 0xc7, 0xae, 0xc6, 0x2e, 0xa6, 0x24, 0x75, 0x70, 0x39, 0x96, 0xda, 0xbc, + 0x2c, 0x59, 0x76, 0xef, 0x41, 0xc9, 0xb4, 0x3c, 0x95, 0xfe, 0xde, 0x06, 0xd7, 0x55, 0x33, 0xd7, + 0x16, 0x4d, 0xcb, 0x3b, 0x76, 0xf1, 0xf0, 0xc0, 0x40, 0x8d, 0x89, 0x46, 0x2f, 0x47, 0xb7, 0xe1, + 0x8d, 0x14, 0xae, 0xb9, 0xbf, 0x11, 0x8f, 0x17, 0xe9, 0xd4, 0xbe, 0x36, 0xd9, 0x3f, 0x5d, 0x4e, + 0x59, 0x84, 0x08, 0x89, 0xb5, 0x70, 0xb5, 0xa7, 0x00, 0x63, 0xad, 0x97, 0x6c, 0x7b, 0x2e, 0x41, + 0xde, 0x7e, 0xf6, 0xcc, 0xc3, 0x2c, 0x92, 0x39, 0x25, 0x18, 0xd5, 0xfa, 0x20, 0x9c, 0x78, 0xd8, + 0x45, 0xe7, 0xa3, 0x50, 0x89, 0x34, 0x26, 0x55, 0x28, 0x0e, 0x3c, 0xec, 0x5a, 0x5a, 0x3f, 0x0c, + 0x4b, 0x34, 0x46, 0xdf, 0x4a, 0xd9, 0x99, 0xd5, 0x3a, 0xbb, 0x25, 0xae, 0x87, 0xb7, 0xc4, 0x54, + 0x0f, 0x7a, 0x8d, 0x1c, 0x53, 0xa3, 0xf6, 0x37, 0x1e, 0x0a, 0xc7, 0xae, 0x4d, 0x0b, 0x71, 0x72, + 0x49, 0x04, 0x42, 0x6c, 0x39, 0xfa, 0x8d, 0xae, 0x01, 0x38, 0x83, 0xd3, 0x9e, 0xa9, 0xd3, 0xab, + 0xe4, 0x2c, 0xa5, 0x88, 0x6c, 0xe6, 0x43, 0x3c, 0x22, 0x64, 0x0f, 0xeb, 0x2e, 0x66, 0x37, 0xcd, + 0x02, 0x23, 0xb3, 0x19, 0x42, 0xde, 0x82, 0xb2, 0x36, 0xf0, 0xbb, 0xea, 0xa7, 0xf8, 0xb4, 0x6b, + 0xdb, 0x67, 0xea, 0xc0, 0xed, 0x05, 0x7f, 0x9f, 0xe7, 0xc9, 0xfc, 0x47, 0x6c, 0xfa, 0xc4, 0xed, + 0xa1, 0x3b, 0xb0, 0x3e, 0x81, 0xec, 0x63, 0xbf, 0x6b, 0x1b, 0x5e, 0x25, 0xbf, 0x99, 0xdd, 0x12, + 0x15, 0x14, 0x43, 0x3f, 0x62, 0x14, 0xb4, 0x03, 0xeb, 0x06, 0xd6, 0x74, 0xdf, 0x1c, 0x6a, 0x3e, + 0x56, 0xfd, 0xae, 0x8b, 0xbd, 0xae, 0xdd, 0x33, 0xe8, 0x75, 0x5e, 0x56, 0x59, 0x1b, 0xd3, 0x3a, + 0x21, 0x29, 0xe1, 0xb7, 0xe2, 0x2b, 0xf8, 0x8d, 0xb0, 0xc6, 0x36, 0xa3, 0xf8, 0xc5, 0xac, 0xe3, + 0x1d, 0xf9, 0x47, 0x1e, 0x2e, 0x9d, 0x90, 0x91, 0x76, 0xda, 0xc3, 0x81, 0xef, 0x3f, 0x30, 0x71, + 0xcf, 0xf0, 0xd0, 0x9d, 0xc0, 0xe3, 0x5c, 0xd0, 0xca, 0x27, 0xe5, 0xb5, 0x7d, 0xd7, 0xb4, 0x9e, + 0xd3, 0xe3, 0x3a, 0x88, 0xc7, 0x07, 0x29, 0x1e, 0xe5, 0x17, 0xe0, 0x4e, 0xfa, 0xfb, 0xd9, 0x0c, + 0x7f, 0xb3, 0x64, 0xba, 0x1b, 0x4b, 0xe7, 0x74, 0xd5, 0xeb, 0xd2, 0x54, 0x44, 0x5e, 0x29, 0x4a, + 0xc2, 0xcc, 0x28, 0x55, 0xeb, 0x80, 0xa6, 0x85, 0xb3, 0x0b, 0x7c, 0xa6, 0x23, 0x47, 0x73, 0x22, + 0x1c, 0xd6, 0xbe, 0xcf, 0xc3, 0xea, 0x7e, 0xf0, 0xb8, 0xd1, 0x1e, 0xf4, 0xfb, 0x9a, 0x3b, 0x9a, + 0x4a, 0xed, 0xe9, 0x0b, 0xd3, 0xe4, 0x5b, 0x86, 0x18, 0x7b, 0xcb, 0x98, 0xcc, 0x13, 0xe1, 0x55, + 0xf2, 0xe4, 0x3e, 0x94, 0x34, 0x5d, 0xc7, 0x9e, 0x17, 0xaf, 0x66, 0xf3, 0x78, 0x21, 0x84, 0x4f, + 0x25, 0x59, 0xfe, 0x55, 0x92, 0xec, 0x47, 0x1c, 0x14, 0x8f, 0x5d, 0xec, 0x61, 0x4b, 0xa7, 0xf5, + 0x5c, 0xef, 0xd9, 0xfa, 0x19, 0x75, 0x40, 0x4e, 0x61, 0x03, 0xd2, 0xf5, 0x93, 0x48, 0x56, 0x78, + 0x7a, 0xb8, 0xc6, 0x2f, 0xae, 0x43, 0xc6, 0xfa, 0xbe, 0xe6, 0x6b, 0xec, 0x58, 0xa5, 0xd0, 0xea, + 0x37, 0x40, 0x8c, 0xa6, 0x5e, 0xe5, 0xa7, 0xb7, 0x76, 0x00, 0xf9, 0x06, 0x7d, 0xff, 0x88, 0x45, + 0x62, 0x85, 0x46, 0x62, 0x1b, 0x8a, 0x4e, 0xb0, 0x5c, 0x90, 0xb8, 0x6b, 0x29, 0x9a, 0x28, 0x11, + 0xa8, 0xf6, 0x2e, 0x14, 0x98, 0x28, 0x8f, 0xbe, 0x31, 0xb1, 0xcf, 0xa0, 0x51, 0x9b, 0x78, 0x63, + 0xa2, 0x14, 0x25, 0x44, 0xd4, 0x5a, 0x00, 0xe3, 0x67, 0xac, 0xc4, 0x1b, 0x0c, 0x97, 0xf6, 0x06, + 0x33, 0xf9, 0x8a, 0xc3, 0x27, 0x5e, 0x71, 0x6a, 0x3f, 0xe0, 0xa0, 0x14, 0xbb, 0x9e, 0x78, 0xbd, + 0x65, 0x00, 0x7d, 0x05, 0x56, 0x5d, 0xdc, 0xd3, 0x48, 0xd3, 0xad, 0x06, 0x80, 0x2c, 0x05, 0x9c, + 0x0f, 0xa7, 0x8f, 0x58, 0xbd, 0xd0, 0x01, 0xc6, 0x92, 0xe3, 0xef, 0x46, 0xdc, 0xf4, 0xbb, 0xd1, + 0x55, 0x10, 0x0d, 0xdc, 0x23, 0xbd, 0x3c, 0x76, 0x43, 0x83, 0xa2, 0x89, 0x89, 0x57, 0xa5, 0xec, + 0xe4, 0xab, 0xd2, 0x8f, 0x39, 0x28, 0xee, 0xdb, 0xba, 0x3c, 0x24, 0x11, 0xbc, 0x3d, 0xd1, 0x47, + 0xc6, 0xeb, 0x65, 0x08, 0x89, 0xb5, 0x92, 0xdb, 0xc0, 0xaa, 0x83, 0xd7, 0x0d, 0x96, 0x4c, 0x0d, + 0xd2, 0x18, 0x83, 0x6e, 0xc0, 0xb9, 0xf8, 0x6b, 0x25, 0x7b, 0x81, 0x13, 0x95, 0x95, 0xd8, 0x73, + 0xa5, 0x77, 0xeb, 0xe7, 0x3c, 0x88, 0x51, 0xd3, 0x8a, 0xd6, 0x60, 0xf5, 0xb1, 0x74, 0x78, 0x22, + 0xab, 0x9d, 0x27, 0xc7, 0xb2, 0xda, 0x3a, 0x39, 0x3c, 0x2c, 0x67, 0xd0, 0x25, 0x40, 0xb1, 0xc9, + 0xbd, 0xa3, 0xa3, 0x43, 0x59, 0x6a, 0x95, 0xb9, 0xc4, 0xfc, 0x41, 0xab, 0x23, 0x3f, 0x90, 0x95, + 0x32, 0x9f, 0x10, 0x72, 0x78, 0xd4, 0x7a, 0x50, 0xce, 0xa2, 0x8b, 0x70, 0x21, 0x36, 0xb9, 0x7f, + 0x74, 0xb2, 0x77, 0x28, 0x97, 0x85, 0xc4, 0x74, 0xbb, 0xa3, 0x1c, 0xb4, 0x1e, 0x94, 0x73, 0x68, + 0x1d, 0xca, 0xf1, 0x25, 0x9f, 0x74, 0xe4, 0x76, 0x39, 0x9f, 0x10, 0xbc, 0x2f, 0x75, 0xe4, 0x72, + 0x01, 0x55, 0xe1, 0x52, 0x6c, 0x92, 0x34, 0x85, 0xea, 0xd1, 0xde, 0x43, 0xb9, 0xd1, 0x29, 0x17, + 0xd1, 0x15, 0xb8, 0x98, 0xa4, 0x49, 0x8a, 0x22, 0x3d, 0x29, 0x8b, 0x09, 0x59, 0x1d, 0xf9, 0x3b, + 0x9d, 0x32, 0x24, 0x64, 0x05, 0x16, 0xa9, 0x8d, 0x56, 0xa7, 0x5c, 0x42, 0x97, 0x61, 0x2d, 0x61, + 0x15, 0x25, 0xac, 0xdc, 0xfa, 0x19, 0x07, 0x2b, 0xf1, 0x70, 0xa1, 0xff, 0x83, 0xcd, 0xfd, 0xa3, + 0x86, 0x2a, 0x3f, 0x96, 0x5b, 0x9d, 0xd0, 0xdc, 0xc6, 0xc9, 0x23, 0xb9, 0xd5, 0x69, 0xab, 0x8d, + 0xa6, 0xd4, 0x7a, 0x20, 0xef, 0x97, 0x33, 0x73, 0x51, 0x1f, 0x49, 0x9d, 0x46, 0x53, 0xde, 0x2f, + 0x73, 0xe8, 0x26, 0xd4, 0x66, 0xa2, 0x4e, 0x5a, 0x21, 0x8e, 0x47, 0x37, 0xe0, 0xed, 0x04, 0xee, + 0x58, 0x91, 0xdb, 0x72, 0xab, 0x21, 0x47, 0x4b, 0x66, 0xf7, 0x6e, 0xff, 0xea, 0xe5, 0x06, 0xf7, + 0x9b, 0x97, 0x1b, 0xdc, 0x9f, 0x5e, 0x6e, 0x70, 0x3f, 0xf9, 0x7c, 0x23, 0x03, 0x17, 0x0c, 0x3c, + 0x0c, 0x73, 0x48, 0x73, 0xcc, 0xfa, 0x70, 0xe7, 0x98, 0x7b, 0x2a, 0xd4, 0xef, 0x0f, 0x77, 0x4e, + 0xf3, 0xf4, 0x54, 0xfc, 0xfa, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x0a, 0x0e, 0x03, 0x25, 0x6a, + 0x1f, 0x00, 0x00, } func (m *ChangePack) Marshal() (dAtA []byte, err error) { @@ -4911,7 +4929,7 @@ func (m *Project) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintResources(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x42 + dAtA[i] = 0x4a } if m.CreatedAt != nil { { @@ -4923,7 +4941,12 @@ func (m *Project) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintResources(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x3a + dAtA[i] = 0x42 + } + if m.DeactivateThreshold != 0 { + i = encodeVarintResources(dAtA, i, uint64(m.DeactivateThreshold)) + i-- + dAtA[i] = 0x38 } if len(m.AuthWebhookMethods) > 0 { for iNdEx := len(m.AuthWebhookMethods) - 1; iNdEx >= 0; iNdEx-- { @@ -4996,6 +5019,11 @@ func (m *UpdatableProjectFields) MarshalToSizedBuffer(dAtA []byte) (int, error) i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.DeactivateThreshold != 0 { + i = encodeVarintResources(dAtA, i, uint64(m.DeactivateThreshold)) + i-- + dAtA[i] = 0x20 + } if m.AuthWebhookMethods != nil { { size, err := m.AuthWebhookMethods.MarshalToSizedBuffer(dAtA[:i]) @@ -6366,6 +6394,9 @@ func (m *Project) Size() (n int) { n += 1 + l + sovResources(uint64(l)) } } + if m.DeactivateThreshold != 0 { + n += 1 + sovResources(uint64(m.DeactivateThreshold)) + } if m.CreatedAt != nil { l = m.CreatedAt.Size() n += 1 + l + sovResources(uint64(l)) @@ -6398,6 +6429,9 @@ func (m *UpdatableProjectFields) Size() (n int) { l = m.AuthWebhookMethods.Size() n += 1 + l + sovResources(uint64(l)) } + if m.DeactivateThreshold != 0 { + n += 1 + sovResources(uint64(m.DeactivateThreshold)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -11961,6 +11995,25 @@ func (m *Project) Unmarshal(dAtA []byte) error { m.AuthWebhookMethods = append(m.AuthWebhookMethods, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DeactivateThreshold", wireType) + } + m.DeactivateThreshold = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowResources + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DeactivateThreshold |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType) } @@ -11996,7 +12049,7 @@ func (m *Project) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 8: + case 9: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field UpdatedAt", wireType) } @@ -12191,6 +12244,25 @@ func (m *UpdatableProjectFields) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DeactivateThreshold", wireType) + } + m.DeactivateThreshold = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowResources + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DeactivateThreshold |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipResources(dAtA[iNdEx:]) diff --git a/api/yorkie/v1/resources.proto b/api/yorkie/v1/resources.proto index 4745b8354..d43d7810b 100644 --- a/api/yorkie/v1/resources.proto +++ b/api/yorkie/v1/resources.proto @@ -214,8 +214,9 @@ message Project { string secret_key = 4; string auth_webhook_url = 5; repeated string auth_webhook_methods = 6; - google.protobuf.Timestamp created_at = 7; - google.protobuf.Timestamp updated_at = 8; + int64 deactivate_threshold = 7; + google.protobuf.Timestamp created_at = 8; + google.protobuf.Timestamp updated_at = 9; } message UpdatableProjectFields { @@ -226,6 +227,7 @@ message UpdatableProjectFields { google.protobuf.StringValue name = 1; google.protobuf.StringValue auth_webhook_url = 2; AuthWebhookMethods auth_webhook_methods = 3; + int64 deactivate_threshold = 4; } message DocumentSummary { diff --git a/cmd/yorkie/server.go b/cmd/yorkie/server.go index c1d8159bc..3f3797c77 100644 --- a/cmd/yorkie/server.go +++ b/cmd/yorkie/server.go @@ -39,9 +39,8 @@ var ( flagConfPath string flagLogLevel string - adminTokenDuration time.Duration - housekeepingInterval time.Duration - housekeepingDeactivateThreshold time.Duration + adminTokenDuration time.Duration + housekeepingInterval time.Duration mongoConnectionURI string mongoConnectionTimeout time.Duration @@ -72,7 +71,6 @@ func newServerCmd() *cobra.Command { conf.Backend.AuthWebhookCacheUnauthTTL = authWebhookCacheUnauthTTL.String() conf.Housekeeping.Interval = housekeepingInterval.String() - conf.Housekeeping.DeactivateThreshold = housekeepingDeactivateThreshold.String() if mongoConnectionURI != "" { conf.Mongo = &mongo.Config{ @@ -224,12 +222,6 @@ func init() { server.DefaultHousekeepingInterval, "housekeeping interval between housekeeping runs", ) - cmd.Flags().DurationVar( - &housekeepingDeactivateThreshold, - "housekeeping-deactivate-threshold", - server.DefaultHousekeepingDeactivateThreshold, - "time after which clients are considered deactivate", - ) cmd.Flags().IntVar( &conf.Housekeeping.CandidatesLimit, "housekeeping-candidates-limit", diff --git a/server/backend/database/client_info.go b/server/backend/database/client_info.go index 793660f73..f6380dd16 100644 --- a/server/backend/database/client_info.go +++ b/server/backend/database/client_info.go @@ -68,6 +68,10 @@ type ClientInfo struct { // Documents is a map of document which is attached to the client. Documents map[types.ID]*ClientDocInfo `bson:"documents"` + // DeactivateThreshold is the time after which clients are + // considered deactivate in specific project. + DeactivateThreshold time.Duration `bson:"deactivate_threshold"` + // CreatedAt is the time when the client was created. CreatedAt time.Time `bson:"created_at"` @@ -193,13 +197,14 @@ func (i *ClientInfo) DeepCopy() *ClientInfo { } return &ClientInfo{ - ID: i.ID, - ProjectID: i.ProjectID, - Key: i.Key, - Status: i.Status, - Documents: documents, - CreatedAt: i.CreatedAt, - UpdatedAt: i.UpdatedAt, + ID: i.ID, + ProjectID: i.ProjectID, + Key: i.Key, + Status: i.Status, + Documents: documents, + DeactivateThreshold: i.DeactivateThreshold, + CreatedAt: i.CreatedAt, + UpdatedAt: i.UpdatedAt, } } diff --git a/server/backend/database/database.go b/server/backend/database/database.go index 08f388729..d794f1009 100644 --- a/server/backend/database/database.go +++ b/server/backend/database/database.go @@ -118,7 +118,12 @@ type Database interface { ListUserInfos(ctx context.Context) ([]*UserInfo, error) // ActivateClient activates the client of the given key. - ActivateClient(ctx context.Context, projectID types.ID, key string) (*ClientInfo, error) + ActivateClient( + ctx context.Context, + projectID types.ID, + deactivateThreshold gotime.Duration, + key string, + ) (*ClientInfo, error) // DeactivateClient deactivates the client of the given ID. DeactivateClient(ctx context.Context, projectID, clientID types.ID) (*ClientInfo, error) @@ -133,7 +138,6 @@ type Database interface { // FindDeactivateCandidates finds the housekeeping candidates. FindDeactivateCandidates( ctx context.Context, - deactivateThreshold gotime.Duration, candidatesLimit int, ) ([]*ClientInfo, error) diff --git a/server/backend/database/memory/database.go b/server/backend/database/memory/database.go index bc902e79a..e26008d0c 100644 --- a/server/backend/database/memory/database.go +++ b/server/backend/database/memory/database.go @@ -366,6 +366,7 @@ func (d *DB) ListUserInfos( func (d *DB) ActivateClient( ctx context.Context, projectID types.ID, + deactivateThreshold gotime.Duration, key string, ) (*database.ClientInfo, error) { txn := d.db.Txn(true) @@ -379,10 +380,11 @@ func (d *DB) ActivateClient( now := gotime.Now() clientInfo := &database.ClientInfo{ - ProjectID: projectID, - Key: key, - Status: database.ClientActivated, - UpdatedAt: now, + ProjectID: projectID, + Key: key, + Status: database.ClientActivated, + DeactivateThreshold: deactivateThreshold, + UpdatedAt: now, } if raw == nil { @@ -527,27 +529,24 @@ func (d *DB) UpdateClientInfoAfterPushPull( // FindDeactivateCandidates finds the clients that need housekeeping. func (d *DB) FindDeactivateCandidates( ctx context.Context, - inactiveThreshold gotime.Duration, candidatesLimit int, ) ([]*database.ClientInfo, error) { txn := d.db.Txn(false) defer txn.Abort() - offset := gotime.Now().Add(-inactiveThreshold) - var infos []*database.ClientInfo iterator, err := txn.ReverseLowerBound( tblClients, "status_updated_at", database.ClientActivated, - offset, ) if err != nil { - return nil, fmt.Errorf("fetch deactivated clients: %w", err) + return nil, fmt.Errorf("fetch currently activated clients: %w", err) } for raw := iterator.Next(); raw != nil; raw = iterator.Next() { info := raw.(*database.ClientInfo) + offset := gotime.Now().Add(-info.DeactivateThreshold) if info.Status != database.ClientActivated || candidatesLimit <= len(infos) || diff --git a/server/backend/database/memory/database_test.go b/server/backend/database/memory/database_test.go index c3904eea1..175b28e29 100644 --- a/server/backend/database/memory/database_test.go +++ b/server/backend/database/memory/database_test.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "testing" + gotime "time" "github.com/stretchr/testify/assert" @@ -42,20 +43,21 @@ func TestDB(t *testing.T) { dummyOwnerID := types.ID("000000000000000000000000") otherOwnerID := types.ID("000000000000000000000001") notExistsID := types.ID("000000000000000000000000") + deactivateThreshold := 1 * gotime.Hour t.Run("activate/deactivate client test", func(t *testing.T) { // try to deactivate the client with not exists ID. _, err = db.DeactivateClient(ctx, projectID, notExistsID) assert.ErrorIs(t, err, database.ErrClientNotFound) - clientInfo, err := db.ActivateClient(ctx, projectID, t.Name()) + clientInfo, err := db.ActivateClient(ctx, projectID, deactivateThreshold, t.Name()) assert.NoError(t, err) assert.Equal(t, t.Name(), clientInfo.Key) assert.Equal(t, database.ClientActivated, clientInfo.Status) // try to activate the client twice. - clientInfo, err = db.ActivateClient(ctx, projectID, t.Name()) + clientInfo, err = db.ActivateClient(ctx, projectID, deactivateThreshold, t.Name()) assert.NoError(t, err) assert.Equal(t, t.Name(), clientInfo.Key) assert.Equal(t, database.ClientActivated, clientInfo.Status) @@ -125,7 +127,7 @@ func TestDB(t *testing.T) { _, err := db.FindClientInfoByID(ctx, projectID, notExistsID) assert.ErrorIs(t, err, database.ErrClientNotFound) - clientInfo, err := db.ActivateClient(ctx, projectID, t.Name()) + clientInfo, err := db.ActivateClient(ctx, projectID, deactivateThreshold, t.Name()) assert.NoError(t, err) found, err := db.FindClientInfoByID(ctx, projectID, clientInfo.ID) @@ -134,7 +136,7 @@ func TestDB(t *testing.T) { }) t.Run("find docInfo test", func(t *testing.T) { - clientInfo, err := db.ActivateClient(ctx, projectID, t.Name()) + clientInfo, err := db.ActivateClient(ctx, projectID, deactivateThreshold, t.Name()) assert.NoError(t, err) docKey := key.Key(fmt.Sprintf("tests$%s", t.Name())) @@ -150,7 +152,7 @@ func TestDB(t *testing.T) { localDB, err := memory.New() assert.NoError(t, err) - clientInfo, err := localDB.ActivateClient(ctx, projectID, t.Name()) + clientInfo, err := localDB.ActivateClient(ctx, projectID, deactivateThreshold, t.Name()) assert.NoError(t, err) docKeys := []string{ @@ -178,7 +180,7 @@ func TestDB(t *testing.T) { }) t.Run("update clientInfo after PushPull test", func(t *testing.T) { - clientInfo, err := db.ActivateClient(ctx, projectID, t.Name()) + clientInfo, err := db.ActivateClient(ctx, projectID, deactivateThreshold, t.Name()) assert.NoError(t, err) docKey := key.Key(fmt.Sprintf("tests$%s", t.Name())) @@ -194,7 +196,7 @@ func TestDB(t *testing.T) { t.Run("insert and find changes test", func(t *testing.T) { docKey := key.Key(fmt.Sprintf("tests$%s", t.Name())) - clientInfo, _ := db.ActivateClient(ctx, projectID, t.Name()) + clientInfo, _ := db.ActivateClient(ctx, projectID, deactivateThreshold, t.Name()) docInfo, _ := db.FindDocInfoByKeyAndOwner(ctx, projectID, clientInfo.ID, docKey, true) assert.NoError(t, clientInfo.AttachDocument(docInfo.ID)) assert.NoError(t, db.UpdateClientInfoAfterPushPull(ctx, clientInfo, docInfo)) @@ -237,7 +239,7 @@ func TestDB(t *testing.T) { ctx := context.Background() docKey := key.Key(fmt.Sprintf("tests$%s", t.Name())) - clientInfo, _ := db.ActivateClient(ctx, projectID, t.Name()) + clientInfo, _ := db.ActivateClient(ctx, projectID, deactivateThreshold, t.Name()) bytesID, _ := clientInfo.ID.Bytes() actorID, _ := time.ActorIDFromBytes(bytesID) docInfo, _ := db.FindDocInfoByKeyAndOwner(ctx, projectID, clientInfo.ID, docKey, true) @@ -289,7 +291,7 @@ func TestDB(t *testing.T) { pageSize := 5 totalSize := 9 - clientInfo, _ := localDB.ActivateClient(ctx, projectID, t.Name()) + clientInfo, _ := localDB.ActivateClient(ctx, projectID, deactivateThreshold, t.Name()) for i := 0; i < totalSize; i++ { _, err := localDB.FindDocInfoByKeyAndOwner(ctx, projectID, clientInfo.ID, key.Key(fmt.Sprintf("%d", i)), true) assert.NoError(t, err) @@ -363,6 +365,7 @@ func TestDB(t *testing.T) { string(types.AttachDocument), string(types.WatchDocuments), } + newDeactivateThreshold := 1 * gotime.Hour info, err := db.CreateProjectInfo(ctx, t.Name(), dummyOwnerID) assert.NoError(t, err) @@ -373,9 +376,10 @@ func TestDB(t *testing.T) { // 01. Update all fields test fields := &types.UpdatableProjectFields{ - Name: &newName, - AuthWebhookURL: &newAuthWebhookURL, - AuthWebhookMethods: &newAuthWebhookMethods, + Name: &newName, + AuthWebhookURL: &newAuthWebhookURL, + AuthWebhookMethods: &newAuthWebhookMethods, + DeactivateThreshold: newDeactivateThreshold.Milliseconds(), } assert.NoError(t, fields.Validate()) res, err := db.UpdateProjectInfo(ctx, dummyOwnerID, id, fields) @@ -386,6 +390,7 @@ func TestDB(t *testing.T) { assert.Equal(t, newName, updateInfo.Name) assert.Equal(t, newAuthWebhookURL, updateInfo.AuthWebhookURL) assert.Equal(t, newAuthWebhookMethods, updateInfo.AuthWebhookMethods) + assert.Equal(t, newDeactivateThreshold, updateInfo.DeactivateThreshold) // 02. Update name field test fields = &types.UpdatableProjectFields{ @@ -400,6 +405,7 @@ func TestDB(t *testing.T) { assert.NotEqual(t, newName, updateInfo.Name) assert.Equal(t, newAuthWebhookURL, updateInfo.AuthWebhookURL) assert.Equal(t, newAuthWebhookMethods, updateInfo.AuthWebhookMethods) + assert.Equal(t, newDeactivateThreshold, updateInfo.DeactivateThreshold) // 03. Update authWebhookURL test newAuthWebhookURL2 := newAuthWebhookURL + "2" @@ -415,13 +421,30 @@ func TestDB(t *testing.T) { assert.Equal(t, newName2, updateInfo.Name) assert.NotEqual(t, newAuthWebhookURL, updateInfo.AuthWebhookURL) assert.Equal(t, newAuthWebhookMethods, updateInfo.AuthWebhookMethods) + assert.Equal(t, newDeactivateThreshold, updateInfo.DeactivateThreshold) - // 04. Duplicated name test + // 04. Update deactivateThreshold test + deactivateThreshold2 := deactivateThreshold + 1*gotime.Hour + fields = &types.UpdatableProjectFields{ + DeactivateThreshold: deactivateThreshold2.Milliseconds(), + } + assert.NoError(t, fields.Validate()) + res, err = db.UpdateProjectInfo(ctx, dummyOwnerID, id, fields) + assert.NoError(t, err) + updateInfo, err = db.FindProjectInfoByID(ctx, id) + assert.NoError(t, err) + assert.Equal(t, res, updateInfo) + assert.Equal(t, newName2, updateInfo.Name) + assert.Equal(t, newAuthWebhookURL2, updateInfo.AuthWebhookURL) + assert.Equal(t, newAuthWebhookMethods, updateInfo.AuthWebhookMethods) + assert.NotEqual(t, newDeactivateThreshold, updateInfo.DeactivateThreshold) + + // 05. Duplicated name test fields = &types.UpdatableProjectFields{Name: &existName} _, err = db.UpdateProjectInfo(ctx, dummyOwnerID, id, fields) assert.ErrorIs(t, err, database.ErrProjectNameAlreadyExists) - // 05. OwnerID not match test + // 06. OwnerID not match test fields = &types.UpdatableProjectFields{Name: &existName} _, err = db.UpdateProjectInfo(ctx, otherOwnerID, id, fields) assert.ErrorIs(t, err, database.ErrProjectNotFound) diff --git a/server/backend/database/memory/housekeeping_test.go b/server/backend/database/memory/housekeeping_test.go index 5589b0d0f..22da3bce1 100644 --- a/server/backend/database/memory/housekeeping_test.go +++ b/server/backend/database/memory/housekeeping_test.go @@ -36,6 +36,7 @@ func TestHousekeeping(t *testing.T) { memdb, err := memory.New() assert.NoError(t, err) projectID := database.DefaultProjectID + deactivateThreshold := 24 * gotime.Hour t.Run("housekeeping test", func(t *testing.T) { ctx := context.Background() @@ -45,21 +46,20 @@ func TestHousekeeping(t *testing.T) { if err != nil { log.Fatal(err) } - clientA, err := memdb.ActivateClient(ctx, projectID, fmt.Sprintf("%s-A", t.Name())) + clientA, err := memdb.ActivateClient(ctx, projectID, deactivateThreshold, fmt.Sprintf("%s-A", t.Name())) assert.NoError(t, err) - clientB, err := memdb.ActivateClient(ctx, projectID, fmt.Sprintf("%s-B", t.Name())) + clientB, err := memdb.ActivateClient(ctx, projectID, deactivateThreshold, fmt.Sprintf("%s-B", t.Name())) assert.NoError(t, err) err = patch.Unpatch() if err != nil { log.Fatal(err) } - clientC, err := memdb.ActivateClient(ctx, projectID, fmt.Sprintf("%s-C", t.Name())) + clientC, err := memdb.ActivateClient(ctx, projectID, deactivateThreshold, fmt.Sprintf("%s-C", t.Name())) assert.NoError(t, err) candidates, err := memdb.FindDeactivateCandidates( ctx, - gotime.Hour, 10, ) assert.NoError(t, err) diff --git a/server/backend/database/mongo/client.go b/server/backend/database/mongo/client.go index 96827632b..6cd945803 100644 --- a/server/backend/database/mongo/client.go +++ b/server/backend/database/mongo/client.go @@ -173,11 +173,12 @@ func (c *Client) ensureDefaultProjectInfo( "_id": encodedID, }, bson.M{ "$setOnInsert": bson.M{ - "name": candidate.Name, - "owner": encodedDefaultUserID, - "public_key": candidate.PublicKey, - "secret_key": candidate.SecretKey, - "created_at": candidate.CreatedAt, + "name": candidate.Name, + "owner": encodedDefaultUserID, + "public_key": candidate.PublicKey, + "secret_key": candidate.SecretKey, + "created_at": candidate.CreatedAt, + "deactivate_threshold": candidate.DeactivateThreshold.Milliseconds(), }, }, options.Update().SetUpsert(true)) if err != nil { @@ -212,11 +213,12 @@ func (c *Client) CreateProjectInfo( info := database.NewProjectInfo(name, owner) result, err := c.collection(colProjects).InsertOne(ctx, bson.M{ - "name": info.Name, - "owner": encodedOwner, - "public_key": info.PublicKey, - "secret_key": info.SecretKey, - "created_at": info.CreatedAt, + "name": info.Name, + "owner": encodedOwner, + "public_key": info.PublicKey, + "secret_key": info.SecretKey, + "created_at": info.CreatedAt, + "deactivate_threshold": info.DeactivateThreshold.Milliseconds(), }) if err != nil { if mongo.IsDuplicateKeyError(err) { @@ -250,6 +252,9 @@ func (c *Client) ListProjectInfos( } var infos []*database.ProjectInfo + for _, info := range infos { + info.ConvertBsonMillisceondToDurationMicrosecond() + } if err := cursor.All(ctx, &infos); err != nil { return nil, fmt.Errorf("fetch project infos: %w", err) } @@ -270,6 +275,7 @@ func (c *Client) FindProjectInfoByPublicKey(ctx context.Context, publicKey strin } return nil, fmt.Errorf("decode project info: %w", err) } + projectInfo.ConvertBsonMillisceondToDurationMicrosecond() return &projectInfo, nil } @@ -297,6 +303,7 @@ func (c *Client) FindProjectInfoByName( } return nil, fmt.Errorf("decode project info: %w", err) } + projectInfo.ConvertBsonMillisceondToDurationMicrosecond() return &projectInfo, nil } @@ -319,6 +326,7 @@ func (c *Client) FindProjectInfoByID(ctx context.Context, id types.ID) (*databas } return nil, fmt.Errorf("decode project info: %w", err) } + projectInfo.ConvertBsonMillisceondToDurationMicrosecond() return &projectInfo, nil } @@ -367,6 +375,7 @@ func (c *Client) UpdateProjectInfo( } return nil, fmt.Errorf("decode project info: %w", err) } + info.ConvertBsonMillisceondToDurationMicrosecond() return &info, nil } @@ -432,7 +441,12 @@ func (c *Client) ListUserInfos( } // ActivateClient activates the client of the given key. -func (c *Client) ActivateClient(ctx context.Context, projectID types.ID, key string) (*database.ClientInfo, error) { +func (c *Client) ActivateClient( + ctx context.Context, + projectID types.ID, + deactivateThreshold gotime.Duration, + key string, +) (*database.ClientInfo, error) { encodedProjectID, err := encodeID(projectID) if err != nil { return nil, err @@ -444,8 +458,9 @@ func (c *Client) ActivateClient(ctx context.Context, projectID types.ID, key str "key": key, }, bson.M{ "$set": bson.M{ - "status": database.ClientActivated, - "updated_at": now, + "status": database.ClientActivated, + "updated_at": now, + "deactivate_threshold": deactivateThreshold.Milliseconds(), }, }, options.Update().SetUpsert(true)) if err != nil { @@ -593,15 +608,30 @@ func (c *Client) UpdateClientInfoAfterPushPull( // FindDeactivateCandidates finds the clients that need housekeeping. func (c *Client) FindDeactivateCandidates( ctx context.Context, - deactivateThreshold gotime.Duration, candidatesLimit int, ) ([]*database.ClientInfo, error) { - cursor, err := c.collection(colClients).Find(ctx, bson.M{ - "status": database.ClientActivated, - "updated_at": bson.M{ - "$lte": gotime.Now().Add(-deactivateThreshold), - }, - }, options.Find().SetLimit(int64(candidatesLimit))) + cursor, err := c.collection(colClients).Aggregate(ctx, mongo.Pipeline{ + // filter currently activated clients + bson.D{{Key: "$match", Value: bson.D{{Key: "status", Value: database.ClientActivated}}}}, + // filter deactivation threshold exceeded clients + bson.D{{Key: "$match", + Value: bson.D{{Key: "$expr", + Value: bson.D{{Key: "$lte", + Value: bson.A{"$updated_at", + bson.D{{Key: "$dateSubtract", + Value: bson.D{ + {Key: "startDate", Value: "$$NOW"}, + {Key: "unit", Value: "millisecond"}, + {Key: "amount", Value: "$deactivate_threshold"}, + }, + }}, + }, + }}, + }}, + }}, + // limit to candidatesLimit + bson.D{{Key: "$limit", Value: candidatesLimit}}, + }) if err != nil { return nil, fmt.Errorf("find deactivate candidates: %w", err) diff --git a/server/backend/database/mongo/client_test.go b/server/backend/database/mongo/client_test.go index 7b8772c05..f60626bab 100644 --- a/server/backend/database/mongo/client_test.go +++ b/server/backend/database/mongo/client_test.go @@ -19,6 +19,7 @@ package mongo_test import ( "context" "testing" + "time" "github.com/stretchr/testify/assert" @@ -58,12 +59,14 @@ func TestClient(t *testing.T) { string(types.AttachDocument), string(types.WatchDocuments), } + newDeactivateThreshold := 1 * time.Hour // update total project_field fields := &types.UpdatableProjectFields{ - Name: &newName, - AuthWebhookURL: &newAuthWebhookURL, - AuthWebhookMethods: &newAuthWebhookMethods, + Name: &newName, + AuthWebhookURL: &newAuthWebhookURL, + AuthWebhookMethods: &newAuthWebhookMethods, + DeactivateThreshold: newDeactivateThreshold.Milliseconds(), } err = fields.Validate() @@ -78,6 +81,7 @@ func TestClient(t *testing.T) { assert.Equal(t, newName, updateInfo.Name) assert.Equal(t, newAuthWebhookURL, updateInfo.AuthWebhookURL) assert.Equal(t, newAuthWebhookMethods, updateInfo.AuthWebhookMethods) + assert.Equal(t, newDeactivateThreshold, updateInfo.DeactivateThreshold) // update one field newName2 := newName + "2" @@ -97,6 +101,7 @@ func TestClient(t *testing.T) { assert.NotEqual(t, newName, updateInfo.Name) assert.Equal(t, newAuthWebhookURL, updateInfo.AuthWebhookURL) assert.Equal(t, newAuthWebhookMethods, updateInfo.AuthWebhookMethods) + assert.Equal(t, newDeactivateThreshold, updateInfo.DeactivateThreshold) // check duplicate name error fields = &types.UpdatableProjectFields{Name: &existName} diff --git a/server/backend/database/project_info.go b/server/backend/database/project_info.go index be0225862..a047be4cc 100644 --- a/server/backend/database/project_info.go +++ b/server/backend/database/project_info.go @@ -30,6 +30,10 @@ var DefaultProjectID = types.ID("000000000000000000000000") // DefaultProjectName is the default project name. var DefaultProjectName = "default" +// DefaultDeactivateThreshold is the default +// deactivate threshold of clients on specific project for housekeeping. +var DefaultDeactivateThreshold = 1 * time.Minute + // ProjectInfo is a struct for project information. type ProjectInfo struct { // ID is the unique ID of the project. @@ -53,6 +57,10 @@ type ProjectInfo struct { // AuthWebhookMethods is the methods that run the authorization webhook. AuthWebhookMethods []string `bson:"auth_webhook_methods"` + // DeactivateThreshold is the time after which clients are + // considered deactivate in specific project. + DeactivateThreshold time.Duration `bson:"deactivate_threshold"` + // CreatedAt is the time when the project was created. CreatedAt time.Time `bson:"created_at"` @@ -61,10 +69,14 @@ type ProjectInfo struct { } // NewProjectInfo creates a new ProjectInfo of the given name. -func NewProjectInfo(name string, owner types.ID) *ProjectInfo { +func NewProjectInfo( + name string, + owner types.ID, +) *ProjectInfo { return &ProjectInfo{ - Name: name, - Owner: owner, + Name: name, + Owner: owner, + DeactivateThreshold: DefaultDeactivateThreshold, // TODO(hackerwins): Use random generated Key. PublicKey: xid.New().String(), SecretKey: xid.New().String(), @@ -75,15 +87,16 @@ func NewProjectInfo(name string, owner types.ID) *ProjectInfo { // ToProjectInfo converts the given types.Project to ProjectInfo. func ToProjectInfo(project *types.Project) *ProjectInfo { return &ProjectInfo{ - ID: project.ID, - Name: project.Name, - Owner: project.Owner, - PublicKey: project.PublicKey, - SecretKey: project.SecretKey, - AuthWebhookURL: project.AuthWebhookURL, - AuthWebhookMethods: project.AuthWebhookMethods, - CreatedAt: project.CreatedAt, - UpdatedAt: project.UpdatedAt, + ID: project.ID, + Name: project.Name, + Owner: project.Owner, + PublicKey: project.PublicKey, + SecretKey: project.SecretKey, + AuthWebhookURL: project.AuthWebhookURL, + AuthWebhookMethods: project.AuthWebhookMethods, + DeactivateThreshold: project.DeactivateThreshold, + CreatedAt: project.CreatedAt, + UpdatedAt: project.UpdatedAt, } } @@ -94,15 +107,16 @@ func (i *ProjectInfo) DeepCopy() *ProjectInfo { } return &ProjectInfo{ - ID: i.ID, - Name: i.Name, - Owner: i.Owner, - PublicKey: i.PublicKey, - SecretKey: i.SecretKey, - AuthWebhookURL: i.AuthWebhookURL, - AuthWebhookMethods: i.AuthWebhookMethods, - CreatedAt: i.CreatedAt, - UpdatedAt: i.UpdatedAt, + ID: i.ID, + Name: i.Name, + Owner: i.Owner, + PublicKey: i.PublicKey, + SecretKey: i.SecretKey, + AuthWebhookURL: i.AuthWebhookURL, + AuthWebhookMethods: i.AuthWebhookMethods, + DeactivateThreshold: i.DeactivateThreshold, + CreatedAt: i.CreatedAt, + UpdatedAt: i.UpdatedAt, } } @@ -117,19 +131,29 @@ func (i *ProjectInfo) UpdateFields(fields *types.UpdatableProjectFields) { if fields.AuthWebhookMethods != nil { i.AuthWebhookMethods = *fields.AuthWebhookMethods } + if fields.DeactivateThreshold != 0 { + i.DeactivateThreshold = time.Duration(fields.DeactivateThreshold) + } } // ToProject converts the ProjectInfo to the Project. func (i *ProjectInfo) ToProject() *types.Project { return &types.Project{ - ID: i.ID, - Name: i.Name, - Owner: i.Owner, - AuthWebhookURL: i.AuthWebhookURL, - AuthWebhookMethods: i.AuthWebhookMethods, - PublicKey: i.PublicKey, - SecretKey: i.SecretKey, - CreatedAt: i.CreatedAt, - UpdatedAt: i.UpdatedAt, + ID: i.ID, + Name: i.Name, + Owner: i.Owner, + AuthWebhookURL: i.AuthWebhookURL, + AuthWebhookMethods: i.AuthWebhookMethods, + DeactivateThreshold: i.DeactivateThreshold, + PublicKey: i.PublicKey, + SecretKey: i.SecretKey, + CreatedAt: i.CreatedAt, + UpdatedAt: i.UpdatedAt, } } + +// ConvertBsonMillisceondToDurationMicrosecond converts mongoDB's bson +// millisecond unit to go time.Duration's microsecond unit. +func (i *ProjectInfo) ConvertBsonMillisceondToDurationMicrosecond() { + i.DeactivateThreshold = i.DeactivateThreshold * time.Millisecond +} diff --git a/server/backend/database/project_info_test.go b/server/backend/database/project_info_test.go index adc6ab671..9ab882841 100644 --- a/server/backend/database/project_info_test.go +++ b/server/backend/database/project_info_test.go @@ -18,6 +18,7 @@ package database_test import ( "testing" + "time" "github.com/stretchr/testify/assert" @@ -33,6 +34,7 @@ func TestProjectInfo(t *testing.T) { testName := "testName" testURL := "testUrl" testMethods := []string{"testMethod"} + testDeactivateThreshold := 1 * time.Hour project.UpdateFields(&types.UpdatableProjectFields{Name: &testName}) assert.Equal(t, testName, project.Name) @@ -43,5 +45,8 @@ func TestProjectInfo(t *testing.T) { project.UpdateFields(&types.UpdatableProjectFields{AuthWebhookMethods: &testMethods}) assert.Equal(t, testMethods, project.AuthWebhookMethods) assert.Equal(t, dummyOwnerID, project.Owner) + + project.UpdateFields(&types.UpdatableProjectFields{DeactivateThreshold: int64(testDeactivateThreshold)}) + assert.Equal(t, testDeactivateThreshold, project.DeactivateThreshold) }) } diff --git a/server/backend/housekeeping/housekeeping.go b/server/backend/housekeeping/housekeeping.go index ce6bfff2f..1efe38734 100644 --- a/server/backend/housekeeping/housekeeping.go +++ b/server/backend/housekeeping/housekeeping.go @@ -39,10 +39,6 @@ type Config struct { // Interval is the time between housekeeping runs. Interval string `yaml:"Interval"` - // deactivateThreshold is the time after which clients are considered - // deactivate. - DeactivateThreshold string `yaml:"DeactivateThreshold"` - // CandidatesLimit is the maximum number of candidates to be returned. CandidatesLimit int `yaml:"CandidatesLimit"` } @@ -57,14 +53,6 @@ func (c *Config) Validate() error { ) } - if _, err := time.ParseDuration(c.DeactivateThreshold); err != nil { - return fmt.Errorf( - `invalid argument %s for "--housekeeping-deactivate-threshold" flag: %w`, - c.Interval, - err, - ) - } - return nil } @@ -111,20 +99,14 @@ func New( return nil, fmt.Errorf("parse interval %s: %w", conf.Interval, err) } - deactivateThreshold, err := time.ParseDuration(conf.DeactivateThreshold) - if err != nil { - return nil, fmt.Errorf("parse deactivate threshold %s: %w", conf.DeactivateThreshold, err) - } - ctx, cancelFunc := context.WithCancel(context.Background()) return &Housekeeping{ database: database, coordinator: coordinator, - interval: interval, - deactivateThreshold: deactivateThreshold, - candidatesLimit: conf.CandidatesLimit, + interval: interval, + candidatesLimit: conf.CandidatesLimit, ctx: ctx, cancelFunc: cancelFunc, @@ -180,7 +162,6 @@ func (h *Housekeeping) deactivateCandidates(ctx context.Context) error { candidates, err := h.database.FindDeactivateCandidates( ctx, - h.deactivateThreshold, h.candidatesLimit, ) if err != nil { diff --git a/server/clients/clients.go b/server/clients/clients.go index ab6c6691c..92b18737b 100644 --- a/server/clients/clients.go +++ b/server/clients/clients.go @@ -41,7 +41,12 @@ func Activate( project *types.Project, clientKey string, ) (*database.ClientInfo, error) { - return db.ActivateClient(ctx, project.ID, clientKey) + return db.ActivateClient( + ctx, + project.ID, + project.DeactivateThreshold, + clientKey, + ) } // Deactivate deactivates the given client. diff --git a/server/config.go b/server/config.go index 8144ee26a..c2cb4ec7e 100644 --- a/server/config.go +++ b/server/config.go @@ -42,9 +42,8 @@ const ( DefaultAdminPort = 11103 - DefaultHousekeepingInterval = time.Minute - DefaultHousekeepingDeactivateThreshold = 7 * 24 * time.Hour - DefaultHousekeepingCandidateLimit = 500 + DefaultHousekeepingInterval = time.Minute + DefaultHousekeepingCandidateLimit = 500 DefaultMongoConnectionURI = "mongodb://localhost:27017" DefaultMongoConnectionTimeout = 5 * time.Second @@ -248,9 +247,8 @@ func newConfig(port int, profilingPort int) *Config { Port: DefaultAdminPort, }, Housekeeping: &housekeeping.Config{ - Interval: DefaultHousekeepingInterval.String(), - DeactivateThreshold: DefaultHousekeepingDeactivateThreshold.String(), - CandidatesLimit: DefaultHousekeepingCandidateLimit, + Interval: DefaultHousekeepingInterval.String(), + CandidatesLimit: DefaultHousekeepingCandidateLimit, }, Backend: &backend.Config{ SnapshotThreshold: DefaultSnapshotThreshold, diff --git a/server/rpc/server_test.go b/server/rpc/server_test.go index e9eb20073..ad507d4b4 100644 --- a/server/rpc/server_test.go +++ b/server/rpc/server_test.go @@ -79,9 +79,8 @@ func TestMain(m *testing.M) { DialTimeout: helper.ETCDDialTimeout.String(), LockLeaseTime: helper.ETCDLockLeaseTime.String(), }, &housekeeping.Config{ - Interval: helper.HousekeepingInterval.String(), - DeactivateThreshold: helper.HousekeepingDeactivateThreshold.String(), - CandidatesLimit: helper.HousekeepingCandidatesLimit, + Interval: helper.HousekeepingInterval.String(), + CandidatesLimit: helper.HousekeepingCandidatesLimit, }, testAdminAddr, met) if err != nil { log.Fatal(err) diff --git a/test/bench/grpc_bench_test.go b/test/bench/grpc_bench_test.go index d98dbb253..c09d8bb21 100644 --- a/test/bench/grpc_bench_test.go +++ b/test/bench/grpc_bench_test.go @@ -25,6 +25,7 @@ import ( "strings" "sync" "testing" + "time" "github.com/stretchr/testify/assert" @@ -108,14 +109,16 @@ func benchmarkUpdateProject(ctx context.Context, b *testing.B, cnt int, adminCli for _, m := range types.AuthMethods() { authWebhookMethods = append(authWebhookMethods, string(m)) } + deactivateThreshold := 1 * time.Hour _, err := adminCli.UpdateProject( ctx, database.DefaultProjectID.String(), &types.UpdatableProjectFields{ - Name: &name, - AuthWebhookURL: &authWebhookURL, - AuthWebhookMethods: &authWebhookMethods, + Name: &name, + AuthWebhookURL: &authWebhookURL, + AuthWebhookMethods: &authWebhookMethods, + DeactivateThreshold: deactivateThreshold, }, ) assert.NoError(b, err) diff --git a/test/helper/helper.go b/test/helper/helper.go index 90f8dbae9..61d867df1 100644 --- a/test/helper/helper.go +++ b/test/helper/helper.go @@ -53,7 +53,6 @@ var ( AdminUser = server.DefaultAdminUser AdminPassword = server.DefaultAdminPassword HousekeepingInterval = 1 * gotime.Second - HousekeepingDeactivateThreshold = 1 * gotime.Minute HousekeepingCandidatesLimit = 10 SnapshotThreshold = int64(10) @@ -125,9 +124,8 @@ func TestConfig() *server.Config { Port: AdminPort + portOffset, }, Housekeeping: &housekeeping.Config{ - Interval: HousekeepingInterval.String(), - DeactivateThreshold: HousekeepingDeactivateThreshold.String(), - CandidatesLimit: HousekeepingCandidatesLimit, + Interval: HousekeepingInterval.String(), + CandidatesLimit: HousekeepingCandidatesLimit, }, Backend: &backend.Config{ AdminUser: server.DefaultAdminUser,