diff --git a/.golangci.yml b/.golangci.yml index 631ef01..14f9120 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,8 +1,5 @@ run: timeout: "5m" - skip-files: - - tools/tools.go - - doc.go linters: disable-all: true @@ -23,6 +20,9 @@ linters: issues: max-issues-per-linter: 0 max-same-issues: 0 + exclude-files: + - tools/tools.go + - doc.go exclude-rules: - path: _test\.go linters: diff --git a/Makefile b/Makefile index 338b2a5..18b9f6f 100644 --- a/Makefile +++ b/Makefile @@ -49,18 +49,13 @@ generate: go run github.com/golang/mock/mockgen github.com/nitrictech/nitric/core/pkg/proto/secrets/v1 SecretManagerClient > mocks/secrets.go go run github.com/golang/mock/mockgen github.com/nitrictech/nitric/core/pkg/proto/topics/v1 TopicsClient > mocks/topics.go go run github.com/golang/mock/mockgen -package mock_v1 google.golang.org/grpc ClientConnInterface > mocks/grpc_clientconn.go - go run github.com/golang/mock/mockgen -package mockapi github.com/nitrictech/go-sdk/api/keyvalue KeyValue,Store > mocks/mockapi/keyvalue.go - go run github.com/golang/mock/mockgen -package mockapi github.com/nitrictech/go-sdk/api/queues Queues,Queue > mocks/mockapi/queues.go - go run github.com/golang/mock/mockgen -package mockapi github.com/nitrictech/go-sdk/api/secrets Secrets,SecretRef > mocks/mockapi/secrets.go - go run github.com/golang/mock/mockgen -package mockapi github.com/nitrictech/go-sdk/api/storage Storage,Bucket > mocks/mockapi/storage.go - go run github.com/golang/mock/mockgen -package mockapi github.com/nitrictech/go-sdk/api/topics Topics,Topic > mocks/mockapi/topics.go # Runs tests for coverage upload to codecov.io test-ci: generate @echo Testing Nitric Go SDK - @go run github.com/onsi/ginkgo/ginkgo -cover -outputdir=./ -coverprofile=all.coverprofile ./resources/... ./api/... ./faas/... + @go run github.com/onsi/ginkgo/ginkgo -cover -outputdir=./ -coverprofile=all.coverprofile ./... .PHONY: test test: generate @echo Testing Nitric Go SDK - @go run github.com/onsi/ginkgo/ginkgo -cover ./resources/... ./api/... ./faas/... \ No newline at end of file + @go run github.com/onsi/ginkgo/ginkgo -cover ./... \ No newline at end of file diff --git a/api/keyvalue/keyvalue.go b/api/keyvalue/keyvalue.go deleted file mode 100644 index 93a0792..0000000 --- a/api/keyvalue/keyvalue.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package keyvalue - -import ( - "context" - - "google.golang.org/grpc" - - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" - "github.com/nitrictech/go-sdk/constants" - v1 "github.com/nitrictech/nitric/core/pkg/proto/kvstore/v1" -) - -// KeyValue - Idiomatic interface for the nitric Key Value Store Service -type KeyValue interface { - // Gets a store instance that refers to the store at the specified path. - Store(string) Store -} - -type keyValueImpl struct { - kvClient v1.KvStoreClient -} - -func (k *keyValueImpl) Store(name string) Store { - return &storeImpl{ - name: name, - kvClient: k.kvClient, - } -} - -// New - Construct a new Key Value Store Client with default options -func New() (KeyValue, error) { - ctx, _ := context.WithTimeout(context.Background(), constants.NitricDialTimeout()) - - conn, err := grpc.DialContext( - ctx, - constants.NitricAddress(), - constants.DefaultOptions()..., - ) - if err != nil { - return nil, errors.NewWithCause( - codes.Unavailable, - "KeyValue.New: Unable to reach KVStoreServiceServer", - err, - ) - } - - kvClient := v1.NewKvStoreClient(conn) - - return &keyValueImpl{ - kvClient: kvClient, - }, nil -} diff --git a/api/keyvalue/keyvalue_test.go b/api/keyvalue/keyvalue_test.go deleted file mode 100644 index fe36b68..0000000 --- a/api/keyvalue/keyvalue_test.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package keyvalue - -import ( - "os" - - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - mock_v1 "github.com/nitrictech/go-sdk/mocks" -) - -var _ = Describe("KeyValue API", func() { - var ( - ctrl *gomock.Controller - mockKV *mock_v1.MockKvStoreClient - kv *keyValueImpl - store Store - storeI *storeImpl - ok bool - storeName string - ) - - BeforeEach(func() { - ctrl = gomock.NewController(GinkgoT()) - mockKV = mock_v1.NewMockKvStoreClient(ctrl) - kv = &keyValueImpl{kvClient: mockKV} - }) - - AfterEach(func() { - ctrl.Finish() - }) - - Describe("Store()", func() { - Context("Given a valid KvStoreClient", func() { - BeforeEach(func() { - storeName = "test-store" - store = kv.Store(storeName) - storeI, ok = store.(*storeImpl) - }) - - When("creating new Store instance", func() { - It("should return an instance of storeImpl", func() { - Expect(ok).To(BeTrue()) - }) - - It("should have the provided store name", func() { - Expect(storeI.name).To(Equal(storeName)) - }) - - It("should share the KeyValue store's gRPC client", func() { - Expect(storeI.kvClient).To(Equal(mockKV)) - }) - }) - }) - }) - - Describe("New method", func() { - When("constructing a new queue client without the membrane", func() { - BeforeEach(func() { - os.Setenv("NITRIC_SERVICE_DIAL_TIMEOUT", "10") - }) - AfterEach(func() { - os.Unsetenv("NITRIC_SERVICE_DIAL_TIMEOUT") - }) - - c, err := New() - - It("should return a nil client", func() { - Expect(c).To(BeNil()) - }) - - It("should return an error", func() { - Expect(err).To(HaveOccurred()) - }) - }) - - PWhen("constructing a new queue client without dial blocking", func() { - // TODO: - }) - }) -}) - -// TODO: new method testing is pending diff --git a/api/queues/queues.go b/api/queues/queues.go deleted file mode 100644 index 4ce23f9..0000000 --- a/api/queues/queues.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package queues - -import ( - "context" - - "google.golang.org/grpc" - - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" - "github.com/nitrictech/go-sdk/constants" - v1 "github.com/nitrictech/nitric/core/pkg/proto/queues/v1" -) - -// Queues - Idiomatic interface for the nitric queue service -type Queues interface { - Queue(string) Queue -} - -type queuesImpl struct { - queueClient v1.QueuesClient -} - -func (q *queuesImpl) Queue(name string) Queue { - return &queueImpl{ - name: name, - queueClient: q.queueClient, - } -} - -// New - Construct a new Queueing Client with default options -func New() (Queues, error) { - ctx, _ := context.WithTimeout(context.Background(), constants.NitricDialTimeout()) - - conn, err := grpc.DialContext( - ctx, - constants.NitricAddress(), - constants.DefaultOptions()..., - ) - if err != nil { - return nil, errors.NewWithCause( - codes.Unavailable, - "Queues.New: Unable to reach QueueServiceServer", - err, - ) - } - - qClient := v1.NewQueuesClient(conn) - - return &queuesImpl{ - queueClient: qClient, - }, nil -} diff --git a/api/queues/queues_test.go b/api/queues/queues_test.go deleted file mode 100644 index 845cf65..0000000 --- a/api/queues/queues_test.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package queues - -import ( - "os" - - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - mock_v1 "github.com/nitrictech/go-sdk/mocks" -) - -var _ = Describe("Queues API", func() { - var ( - ctrl *gomock.Controller - mockQ *mock_v1.MockQueuesClient - queues *queuesImpl - ) - - BeforeEach(func() { - ctrl = gomock.NewController(GinkgoT()) - mockQ = mock_v1.NewMockQueuesClient(ctrl) - queues = &queuesImpl{ - queueClient: mockQ, - } - }) - - AfterEach(func() { - ctrl.Finish() - }) - - Describe("Queue method", func() { - When("creating a new Queue reference", func() { - var ( - q Queue - queueName string - qImpl *queueImpl - ok bool - ) - - BeforeEach(func() { - queueName = "test-queue" - q = queues.Queue(queueName) - qImpl, ok = q.(*queueImpl) - }) - - It("should be an instance of queueImpl", func() { - Expect(ok).To(BeTrue()) - }) - - It("should have the provided queue name", func() { - Expect(q.Name()).To(Equal(queueName)) - }) - - It("should share the Queue's gRPC client", func() { - Expect(qImpl.queueClient).To(Equal(mockQ)) - }) - }) - }) - - Describe("New method", func() { - When("constructing a new queue client without the membrane", func() { - BeforeEach(func() { - os.Setenv("NITRIC_SERVICE_DIAL_TIMEOUT", "10") - }) - AfterEach(func() { - os.Unsetenv("NITRIC_SERVICE_DIAL_TIMEOUT") - }) - - c, err := New() - - It("should return a nil client", func() { - Expect(c).To(BeNil()) - }) - - It("should return an error", func() { - Expect(err).To(HaveOccurred()) - }) - }) - - PWhen("constructing a new queue client without dial blocking", func() { - // TODO: - }) - }) -}) \ No newline at end of file diff --git a/api/secrets/secret_ref.go b/api/secrets/secret_ref.go deleted file mode 100644 index dc7d1aa..0000000 --- a/api/secrets/secret_ref.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package secrets - -import ( - "context" - - "github.com/nitrictech/go-sdk/api/errors" - v1 "github.com/nitrictech/nitric/core/pkg/proto/secrets/v1" -) - -// SecretRef is a reference to a cloud secret for secret storage. -type SecretRef interface { - Name() string - Put(context.Context, []byte) (SecretVersionRef, error) - Version(string) SecretVersionRef - Latest() SecretVersionRef -} - -type secretRefImpl struct { - name string - secretClient v1.SecretManagerClient -} - -func (s *secretRefImpl) Name() string { - return s.name -} - -func (s *secretRefImpl) Put(ctx context.Context, sec []byte) (SecretVersionRef, error) { - resp, err := s.secretClient.Put(ctx, &v1.SecretPutRequest{ - Secret: &v1.Secret{ - Name: s.name, - }, - Value: sec, - }) - if err != nil { - return nil, errors.FromGrpcError(err) - } - - return &secretVersionRefImpl{ - secretClient: s.secretClient, - version: resp.GetSecretVersion().Version, - secret: s, - }, nil -} - -func (s *secretRefImpl) Version(name string) SecretVersionRef { - return &secretVersionRefImpl{ - secret: s, - secretClient: s.secretClient, - version: name, - } -} - -func (s *secretRefImpl) Latest() SecretVersionRef { - return s.Version("latest") -} diff --git a/api/secrets/secret_value_test.go b/api/secrets/secret_value_test.go deleted file mode 100644 index 15ed22d..0000000 --- a/api/secrets/secret_value_test.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package secrets - -import ( - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - mock_v1 "github.com/nitrictech/go-sdk/mocks" -) - -var _ = Describe("secretValueImpl", func() { - var ( - ctrl *gomock.Controller - mockSC *mock_v1.MockSecretManagerClient - secretName string - versionName string - sv SecretVersionRef - secretValue SecretValue - value []byte - ) - - BeforeEach(func() { - ctrl = gomock.NewController(GinkgoT()) - mockSC = mock_v1.NewMockSecretManagerClient(ctrl) - secretName = "test-secret" - versionName = "test-version" - - sv = &secretVersionRefImpl{ - secretClient: mockSC, - secret: &secretRefImpl{ - name: secretName, - secretClient: mockSC, - }, - version: versionName, - } - - value = []byte("ssssshhhh... it's a secret") - secretValue = &secretValueImpl{ - version: sv, - val: value, - } - }) - - AfterEach(func() { - ctrl.Finish() - }) - - Describe("Version", func() { - It("should return the correct secret version reference", func() { - Expect(secretValue.Version()).To(Equal(sv)) - }) - }) - - Describe("AsBytes", func() { - It("should return the correct secret value as bytes", func() { - Expect(secretValue.AsBytes()).To(Equal(value)) - }) - }) - - Describe("AsString", func() { - It("should return the correct secret value as string", func() { - Expect(secretValue.AsString()).To(Equal(string(value))) - }) - }) -}) diff --git a/api/secrets/secret_version_ref.go b/api/secrets/secret_version_ref.go deleted file mode 100644 index bf68513..0000000 --- a/api/secrets/secret_version_ref.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package secrets - -import ( - "context" - - "github.com/nitrictech/go-sdk/api/errors" - v1 "github.com/nitrictech/nitric/core/pkg/proto/secrets/v1" -) - -// SecretVersionRef - A reference to a secret version -type SecretVersionRef interface { - // Access - Retrieve the value of the secret - Access(ctx context.Context) (SecretValue, error) - Secret() SecretRef - Version() string -} - -type secretVersionRefImpl struct { - secretClient v1.SecretManagerClient - secret SecretRef - version string -} - -func (s *secretVersionRefImpl) Secret() SecretRef { - return s.secret -} - -func (s *secretVersionRefImpl) Version() string { - return s.version -} - -func (s *secretVersionRefImpl) Access(ctx context.Context) (SecretValue, error) { - r, err := s.secretClient.Access(ctx, &v1.SecretAccessRequest{ - SecretVersion: &v1.SecretVersion{ - Secret: &v1.Secret{ - Name: s.secret.Name(), - }, - Version: s.version, - }, - }) - if err != nil { - return nil, errors.FromGrpcError(err) - } - - return &secretValueImpl{ - version: &secretVersionRefImpl{ - secretClient: s.secretClient, - secret: s.secret, - version: r.GetSecretVersion().GetVersion(), - }, - val: r.GetValue(), - }, nil -} diff --git a/api/secrets/secret_version_ref_test.go b/api/secrets/secret_version_ref_test.go deleted file mode 100644 index 637926b..0000000 --- a/api/secrets/secret_version_ref_test.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package secrets - -import ( - "context" - "errors" - "strings" - - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - mock_v1 "github.com/nitrictech/go-sdk/mocks" - v1 "github.com/nitrictech/nitric/core/pkg/proto/secrets/v1" -) - -var _ = Describe("secretVersionRefImpl", func() { - var ( - ctrl *gomock.Controller - mockSC *mock_v1.MockSecretManagerClient - secretName string - versionName string - sv SecretVersionRef - sr SecretRef - ctx context.Context - ) - - BeforeEach(func() { - ctrl = gomock.NewController(GinkgoT()) - mockSC = mock_v1.NewMockSecretManagerClient(ctrl) - secretName = "test-secret" - versionName = "test-version" - - sr = &secretRefImpl{ - name: secretName, - secretClient: mockSC, - } - - sv = &secretVersionRefImpl{ - secretClient: mockSC, - secret: sr, - version: versionName, - } - ctx = context.Background() - }) - - AfterEach(func() { - ctrl.Finish() - }) - - Describe("Access", func() { - var secretValue []byte - - BeforeEach(func() { - secretValue = []byte("super-secret-value") - }) - - When("the RPC operation is successful", func() { - BeforeEach(func() { - mockSC.EXPECT().Access(gomock.Any(), &v1.SecretAccessRequest{ - SecretVersion: &v1.SecretVersion{ - Secret: &v1.Secret{ - Name: secretName, - }, - Version: versionName, - }, - }).Return( - &v1.SecretAccessResponse{ - SecretVersion: &v1.SecretVersion{ - Secret: &v1.Secret{ - Name: secretName, - }, - Version: versionName, - }, - Value: secretValue, - }, nil, - ) - }) - - It("should return the secret value", func() { - svValue, err := sv.Access(ctx) - - By("not returning an error") - Expect(err).ToNot(HaveOccurred()) - - By("returning a SecretValue") - Expect(svValue).ToNot(BeNil()) - - By("returning the correct secret value") - Expect(svValue.AsBytes()).To(Equal(secretValue)) - - By("returning the correct secret version") - Expect(svValue.Version().Version()).To(Equal(versionName)) - }) - }) - - When("the RPC operation fails", func() { - var errorMsg string - - BeforeEach(func() { - errorMsg = "Internal Error" - mockSC.EXPECT().Access(gomock.Any(), gomock.Any()).Return( - nil, - errors.New(errorMsg), - ).Times(1) - }) - - It("should return an error", func() { - svValue, err := sv.Access(ctx) - - By("returning the error") - Expect(err).To(HaveOccurred()) - Expect(strings.Contains(err.Error(), errorMsg)).To(BeTrue()) - - By("returning a nil SecretValue") - Expect(svValue).To(BeNil()) - }) - }) - }) - - Context("Version", func() { - When("retrieving the version of a secretVersionRefImpl", func() { - It("should return it's internal version field", func() { - Expect(sv.Version()).To(Equal(versionName)) - }) - }) - }) - - Context("Secret", func() { - When("retrieving the parent secret of a secretVersionRefImpl", func() { - It("should return it's internal secret field", func() { - Expect(sv.Secret()).To(Equal(sr)) - }) - }) - }) -}) diff --git a/api/secrets/secrets.go b/api/secrets/secrets.go deleted file mode 100644 index 93357dd..0000000 --- a/api/secrets/secrets.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package secrets - -import ( - "context" - - "google.golang.org/grpc" - - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" - "github.com/nitrictech/go-sdk/constants" - v1 "github.com/nitrictech/nitric/core/pkg/proto/secrets/v1" -) - -// Secrets - Base client for the Nitric Secrets service -type Secrets interface { - // Secret - Creates a new secret reference - Secret(string) SecretRef -} - -type secretsImpl struct { - secretClient v1.SecretManagerClient -} - -func (s *secretsImpl) Secret(name string) SecretRef { - return &secretRefImpl{ - name: name, - secretClient: s.secretClient, - } -} - -// New - Create a new Secrets client -func New() (Secrets, error) { - ctx, _ := context.WithTimeout(context.Background(), constants.NitricDialTimeout()) - - conn, err := grpc.DialContext( - ctx, - constants.NitricAddress(), - constants.DefaultOptions()..., - ) - if err != nil { - return nil, errors.NewWithCause( - codes.Unavailable, - "Secrets.New: Unable to reach SecretsServiceServer", - err, - ) - } - - sClient := v1.NewSecretManagerClient(conn) - - return &secretsImpl{ - secretClient: sClient, - }, nil -} diff --git a/api/secrets/secrets_test.go b/api/secrets/secrets_test.go deleted file mode 100644 index c4a5270..0000000 --- a/api/secrets/secrets_test.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package secrets - -import ( - "os" - - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - mock_v1 "github.com/nitrictech/go-sdk/mocks" -) - -var _ = Describe("Secrets API", func() { - var ( - ctrl *gomock.Controller - mockSC *mock_v1.MockSecretManagerClient - secrets *secretsImpl - ) - - BeforeEach(func() { - ctrl = gomock.NewController(GinkgoT()) - mockSC = mock_v1.NewMockSecretManagerClient(ctrl) - secrets = &secretsImpl{ - secretClient: mockSC, - } - }) - - AfterEach(func() { - ctrl.Finish() - }) - - Describe("Secret method", func() { - When("creating a new Secret reference", func() { - var ( - sr SecretRef - secretsName string - srImpl *secretRefImpl - ok bool - ) - - BeforeEach(func() { - secretsName = "test-secret" - sr = secrets.Secret(secretsName) - srImpl, ok = sr.(*secretRefImpl) - }) - - It("should be an instance of secretsImpl", func() { - Expect(ok).To(BeTrue()) - }) - - It("should have the provided secrets name", func() { - Expect(sr.Name()).To(Equal(secretsName)) - }) - - It("should share the Secret's gRPC client", func() { - Expect(srImpl.secretClient).To(Equal(mockSC)) - }) - }) - }) - - Describe("New method", func() { - When("Constructing a new Secrets client with no rpc server available", func() { - BeforeEach(func() { - os.Setenv("NITRIC_SERVICE_DIAL_TIMEOUT", "10") - - }) - AfterEach(func() { - os.Unsetenv("NITRIC_SERVICE_DIAL_TIMEOUT") - }) - - c, err := New() - - It("should return a nil client", func() { - Expect(c).To(BeNil()) - }) - - It("should return an error", func() { - Expect(err).To(HaveOccurred()) - }) - }) - - PWhen("constructing a new Secrets client without dial blocking", func() { - // TODO: - }) - }) -}) diff --git a/api/storage/bucket.go b/api/storage/bucket.go deleted file mode 100644 index 537be8d..0000000 --- a/api/storage/bucket.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package storage - -import ( - "context" - - v1 "github.com/nitrictech/nitric/core/pkg/proto/storage/v1" -) - -// Cloud storage bucket resource for large file storage. -type Bucket interface { - // File - Get a file reference for in this bucket - File(key string) File - // Files - Get all file references for this bucket - Files(ctx context.Context) ([]File, error) - // Name - Get the name of the bucket - Name() string -} - -type bucketImpl struct { - storageClient v1.StorageClient - name string -} - -func (b *bucketImpl) File(key string) File { - return &fileImpl{ - storageClient: b.storageClient, - bucket: b.name, - key: key, - } -} - -func (b *bucketImpl) Files(ctx context.Context) ([]File, error) { - resp, err := b.storageClient.ListBlobs(ctx, &v1.StorageListBlobsRequest{ - BucketName: b.name, - }) - if err != nil { - return nil, err - } - - fileRefs := make([]File, 0) - - for _, f := range resp.Blobs { - fileRefs = append(fileRefs, &fileImpl{ - storageClient: b.storageClient, - bucket: b.name, - key: f.Key, - }) - } - - return fileRefs, nil -} - -func (b *bucketImpl) Name() string { - return b.name -} diff --git a/api/storage/file.go b/api/storage/file.go deleted file mode 100644 index 180c138..0000000 --- a/api/storage/file.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package storage - -import ( - "context" - "fmt" - "time" - - "google.golang.org/protobuf/types/known/durationpb" - - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" - v1 "github.com/nitrictech/nitric/core/pkg/proto/storage/v1" -) - -type Mode int - -const ( - ModeRead Mode = iota - ModeWrite -) - -// File - A file reference for a bucket -type File interface { - // Name - Get the name of the file - Name() string - // Read - Read this object - Read(ctx context.Context) ([]byte, error) - // Write - Write this object - Write(ctx context.Context, data []byte) error - // Delete - Delete this object - Delete(ctx context.Context) error - // UploadUrl - Creates a signed Url for uploading this file reference - UploadUrl(ctx context.Context, expiry time.Duration) (string, error) - // DownloadUrl - Creates a signed Url for downloading this file reference - DownloadUrl(ctx context.Context, expiry time.Duration) (string, error) -} - -type fileImpl struct { - bucket string - key string - storageClient v1.StorageClient -} - -func (o *fileImpl) Name() string { - return o.key -} - -func (o *fileImpl) Read(ctx context.Context) ([]byte, error) { - r, err := o.storageClient.Read(ctx, &v1.StorageReadRequest{ - BucketName: o.bucket, - Key: o.key, - }) - if err != nil { - return nil, errors.FromGrpcError(err) - } - - return r.GetBody(), nil -} - -func (o *fileImpl) Write(ctx context.Context, content []byte) error { - if _, err := o.storageClient.Write(ctx, &v1.StorageWriteRequest{ - BucketName: o.bucket, - Key: o.key, - Body: content, - }); err != nil { - return errors.FromGrpcError(err) - } - - return nil -} - -func (o *fileImpl) Delete(ctx context.Context) error { - if _, err := o.storageClient.Delete(ctx, &v1.StorageDeleteRequest{ - BucketName: o.bucket, - Key: o.key, - }); err != nil { - return errors.FromGrpcError(err) - } - - return nil -} - -type PresignUrlOptions struct { - Mode Mode - Expiry time.Duration -} - -func (p PresignUrlOptions) isValid() error { - if p.Mode != ModeRead && p.Mode != ModeWrite { - return fmt.Errorf("invalid mode: %d", p.Mode) - } - - return nil -} - -func (o *fileImpl) UploadUrl(ctx context.Context, expiry time.Duration) (string, error) { - return o.signUrl(ctx, PresignUrlOptions{Expiry: expiry, Mode: ModeWrite}) -} - -func (o *fileImpl) DownloadUrl(ctx context.Context, expiry time.Duration) (string, error) { - return o.signUrl(ctx, PresignUrlOptions{Expiry: expiry, Mode: ModeRead}) -} - -func (o *fileImpl) signUrl(ctx context.Context, opts PresignUrlOptions) (string, error) { - if err := opts.isValid(); err != nil { - return "", errors.NewWithCause(codes.InvalidArgument, "invalid options", err) - } - - op := v1.StoragePreSignUrlRequest_READ - - if opts.Mode == ModeWrite { - op = v1.StoragePreSignUrlRequest_WRITE - } - - r, err := o.storageClient.PreSignUrl(ctx, &v1.StoragePreSignUrlRequest{ - BucketName: o.bucket, - Key: o.key, - Operation: op, - Expiry: durationpb.New(opts.Expiry), - }) - if err != nil { - return "", errors.FromGrpcError(err) - } - - return r.Url, nil -} diff --git a/api/storage/file_test.go b/api/storage/file_test.go deleted file mode 100644 index d216514..0000000 --- a/api/storage/file_test.go +++ /dev/null @@ -1,499 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package storage - -import ( - "context" - "errors" - "strings" - "time" - - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "google.golang.org/protobuf/types/known/durationpb" - - "github.com/nitrictech/go-sdk/api/errors/codes" - mock_v1 "github.com/nitrictech/go-sdk/mocks" - v1 "github.com/nitrictech/nitric/core/pkg/proto/storage/v1" -) - -var _ = Describe("File", func() { - var ( - ctrl *gomock.Controller - mockStorage *mock_v1.MockStorageClient - bucket *bucketImpl - file File - bucketName string - fileName string - ctx context.Context - ) - - BeforeEach(func() { - ctrl = gomock.NewController(GinkgoT()) - mockStorage = mock_v1.NewMockStorageClient(ctrl) - - bucketName = "test-bucket" - fileName = "test-file.txt" - - bucket = &bucketImpl{ - name: bucketName, - storageClient: mockStorage, - } - file = bucket.File(fileName) - - ctx = context.Background() - }) - - AfterEach(func() { - ctrl.Finish() - }) - - Describe("Name()", func() { - It("should have the same file name as the one provided", func() { - _fileName := file.Name() - Expect(_fileName).To(Equal(fileName)) - }) - }) - - Describe("Read()", func() { - When("the gRPC Read operation is successful", func() { - var fileContent []byte - - BeforeEach(func() { - fileContent = []byte("this is dummy file content for testing") - - By("the gRPC server returning a successful response") - mockStorage.EXPECT().Read(gomock.Any(), &v1.StorageReadRequest{ - BucketName: bucketName, - Key: fileName, - }).Return(&v1.StorageReadResponse{ - Body: fileContent, - }, nil).Times(1) - }) - - It("should return the read bytes", func() { - fileData, err := file.Read(ctx) - - By("not returning any error") - Expect(err).ToNot(HaveOccurred()) - - By("returning the expected data in file") - Expect(fileData).To(Equal(fileContent)) - }) - }) - - When("the grpc server returns an error", func() { - var errorMsg string - - BeforeEach(func() { - errorMsg = "Internal Error" - - By("the gRPC server returning an error") - mockStorage.EXPECT().Read(gomock.Any(), gomock.Any()).Return( - nil, - errors.New(errorMsg), - ).Times(1) - }) - - It("should return the passed error", func() { - fileData, err := file.Read(ctx) - - By("returning error with expected message") - Expect(err).To(HaveOccurred()) - Expect(strings.Contains(err.Error(), errorMsg)).To(BeTrue()) - - By("returning nil as file data") - Expect(fileData).To(BeNil()) - }) - }) - }) - - Describe("Write", func() { - var fileData []byte - - BeforeEach(func() { - fileData = []byte("this is dummy file content for testing") - }) - - When("the gRPC write operation is successful", func() { - BeforeEach(func() { - By("the gRPC server returning a successful response") - mockStorage.EXPECT().Write(gomock.Any(), &v1.StorageWriteRequest{ - BucketName: bucketName, - Key: fileName, - Body: fileData, - }).Return( - &v1.StorageWriteResponse{}, - nil, - ).Times(1) - }) - - It("should not return an error", func() { - err := file.Write(ctx, fileData) - Expect(err).ToNot(HaveOccurred()) - }) - }) - - When("the grpc server returns an error", func() { - var errorMsg string - - BeforeEach(func() { - errorMsg = "Internal Error" - - By("the gRPC server returning an error") - mockStorage.EXPECT().Write(gomock.Any(), gomock.Any()).Return( - nil, - errors.New(errorMsg), - ).Times(1) - }) - - It("should return the passed error", func() { - err := file.Write(ctx, fileData) - - By("returning error with expected message") - Expect(err).To(HaveOccurred()) - Expect(strings.Contains(err.Error(), errorMsg)).To(BeTrue()) - }) - }) - }) - - Describe("Delete", func() { - When("the delete gRPC operation is successful", func() { - BeforeEach(func() { - By("the gRPC server returning a successful response") - mockStorage.EXPECT().Delete(gomock.Any(), gomock.Any()).Return( - &v1.StorageDeleteResponse{}, - nil, - ).Times(1) - }) - - It("should not return an error", func() { - err := file.Delete(ctx) - Expect(err).ToNot(HaveOccurred()) - }) - }) - - When("the grpc server returns an error", func() { - var errorMsg string - - BeforeEach(func() { - errorMsg = "Internal Error" - - By("the gRPC server returning an error") - mockStorage.EXPECT().Delete(gomock.Any(), gomock.Any()).Return( - nil, - errors.New(errorMsg), - ).Times(1) - }) - - It("should pass through the returned error", func() { - err := file.Delete(ctx) - - By("returning error with expected message") - Expect(err).To(HaveOccurred()) - Expect(strings.Contains(err.Error(), errorMsg)).To(BeTrue()) - }) - }) - }) - - Describe("UploadUrl()", func() { - var expiry time.Duration - - BeforeEach(func() { - expiry = 1 * time.Hour // 1 hour - }) - - When("the PreSignUrl gRPC operation is successful", func() { - var url string - - BeforeEach(func() { - url = "https://example.com" - - mockStorage.EXPECT().PreSignUrl(ctx, &v1.StoragePreSignUrlRequest{ - BucketName: bucketName, - Key: fileName, - Operation: v1.StoragePreSignUrlRequest_WRITE, - Expiry: durationpb.New(expiry), - }).Return(&v1.StoragePreSignUrlResponse{ - Url: url, - }, nil).Times(1) - }) - - It("should return a valid url stirng", func() { - _url, err := file.UploadUrl(ctx, expiry) - - By("not returning any errors") - Expect(err).ToNot(HaveOccurred()) - By("returning a valid url") - Expect(_url).To(Equal(url)) - }) - }) - - When("the grpc server returns an error", func() { - var errorMsg string - - BeforeEach(func() { - errorMsg = "Internal Error" - - mockStorage.EXPECT().PreSignUrl(gomock.Any(), gomock.Any()).Return( - &v1.StoragePreSignUrlResponse{ - Url: "", - }, - errors.New(errorMsg), - ).Times(1) - }) - - It("should pass through the returned error", func() { - _url, err := file.UploadUrl(ctx, expiry) - - By("returning error with expected message") - Expect(err).To(HaveOccurred()) - Expect(strings.Contains(err.Error(), errorMsg)).To(BeTrue()) - - By("returning empty string url") - Expect(_url).To(Equal("")) - }) - }) - }) - - Describe("DownloadUrl()", func() { - var expiry time.Duration - - BeforeEach(func() { - expiry = 1 * time.Hour // 1 hour - }) - - When("the PreSignUrl gRPC operation is successful", func() { - var url string - - BeforeEach(func() { - url = "https://example.com" - - mockStorage.EXPECT().PreSignUrl(ctx, &v1.StoragePreSignUrlRequest{ - BucketName: bucketName, - Key: fileName, - Operation: v1.StoragePreSignUrlRequest_READ, - Expiry: durationpb.New(expiry), - }).Return(&v1.StoragePreSignUrlResponse{ - Url: url, - }, nil).Times(1) - }) - - It("should return a valid url stirng", func() { - _url, err := file.DownloadUrl(ctx, expiry) - - By("not returning any errors") - Expect(err).ToNot(HaveOccurred()) - By("returning a valid url") - Expect(_url).To(Equal(url)) - }) - }) - - When("the grpc server returns an error", func() { - var errorMsg string - - BeforeEach(func() { - errorMsg = "Internal Error" - - mockStorage.EXPECT().PreSignUrl(gomock.Any(), gomock.Any()).Return( - &v1.StoragePreSignUrlResponse{ - Url: "", - }, - errors.New(errorMsg), - ).Times(1) - }) - - It("should pass through the returned error", func() { - _url, err := file.DownloadUrl(ctx, expiry) - - By("returning error with expected message") - Expect(err).To(HaveOccurred()) - Expect(strings.Contains(err.Error(), errorMsg)).To(BeTrue()) - - By("returning empty string url") - Expect(_url).To(Equal("")) - }) - }) - }) -}) - -var _ = Describe("fileImpl", func() { - var ( - ctrl *gomock.Controller - mockStorage *mock_v1.MockStorageClient - bucket *bucketImpl - file File - fileI *fileImpl - bucketName string - fileName string - ok bool - ctx context.Context - ) - - BeforeEach(func() { - ctrl = gomock.NewController(GinkgoT()) - mockStorage = mock_v1.NewMockStorageClient(ctrl) - - bucketName = "test-bucket" - fileName = "test-file.txt" - - bucket = &bucketImpl{ - name: bucketName, - storageClient: mockStorage, - } - file = bucket.File(fileName) - - By("accessing fileImpl from file") - fileI, ok = file.(*fileImpl) - Expect(ok).To(BeTrue()) - - ctx = context.Background() - }) - - AfterEach(func() { - ctrl.Finish() - }) - - Describe("signUrl()", func() { - var expiry time.Duration - - BeforeEach(func() { - expiry = 1 * time.Hour // 1 hour - }) - - When("invalid mode is provided", func() { - It("should return an error", func() { - _, err := fileI.signUrl(ctx, PresignUrlOptions{ - Mode: 9999, // Invalid Mode - Expiry: expiry, - }) - Expect(err).Should(HaveOccurred()) - Expect(strings.Contains(err.Error(), codes.InvalidArgument.String())).To(BeTrue()) - }) - }) - - When("The grpc server returns an error", func() { - var errorMsg string - - BeforeEach(func() { - errorMsg = "Internal Error" - - By("the gRPC server returning an error") - mockStorage.EXPECT().PreSignUrl(gomock.Any(), &v1.StoragePreSignUrlRequest{ - BucketName: bucketName, - Key: fileName, - Operation: v1.StoragePreSignUrlRequest_READ, - Expiry: durationpb.New(expiry), - }).Return(nil, errors.New(errorMsg)).Times(1) - }) - - It("should pass through the returned error", func() { - _url, err := fileI.signUrl(ctx, PresignUrlOptions{ - Mode: ModeRead, - Expiry: expiry, - }) - - By("returning error with expected message") - Expect(err).To(HaveOccurred()) - Expect(strings.Contains(err.Error(), errorMsg)).To(BeTrue()) - - By("returning empty string url") - Expect(_url).To(Equal("")) - }) - }) - - When("the PreSignUrl operation is successful", func() { - var url string - var mode Mode - - BeforeEach(func() { - url = "http://example.com" - mode = ModeWrite - - mockStorage.EXPECT().PreSignUrl(gomock.Any(), &v1.StoragePreSignUrlRequest{ - BucketName: bucketName, - Key: fileName, - Operation: v1.StoragePreSignUrlRequest_WRITE, - Expiry: durationpb.New(expiry), - }).Return(&v1.StoragePreSignUrlResponse{ - Url: url, - }, nil) - }) - - It("should return a success response", func() { - _url, err := fileI.signUrl(ctx, PresignUrlOptions{Mode: mode, Expiry: expiry}) - - By("no error being returned") - Expect(err).ToNot(HaveOccurred()) - - By("return expected url string") - Expect(_url).To(Equal(url)) - }) - }) - }) -}) - -var _ = Describe("PresignUrlOptions", func() { - var mode Mode - var expiry time.Duration - var p *PresignUrlOptions - - Describe("isValid()", func() { - When("valid mode and expiry are passed", func() { - BeforeEach(func() { - expiry = 1 * time.Hour // 1 hour - mode = ModeRead - - p = &PresignUrlOptions{ - Mode: mode, - Expiry: expiry, - } - }) - - It("should not return an error", func() { - err := p.isValid() - Expect(err).ToNot(HaveOccurred()) - }) - }) - - When("invalid mode is passed", func() { - var errorMsg string - - BeforeEach(func() { - errorMsg = "invalid mode" - expiry = 1 * time.Hour // 1 hour - - p = &PresignUrlOptions{ - Mode: 7, - Expiry: expiry, - } - }) - - It("should return an error", func() { - err := p.isValid() - By("occurance of error") - Expect(err).To(HaveOccurred()) - - By("containing appropriate error message") - Expect(strings.Contains( - strings.ToLower(err.Error()), - strings.ToLower(errorMsg), - ), - ).To(BeTrue()) - }) - }) - }) -}) diff --git a/api/storage/storage.go b/api/storage/storage.go deleted file mode 100644 index 11fe0de..0000000 --- a/api/storage/storage.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package storage - -import ( - "context" - - "google.golang.org/grpc" - - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" - "github.com/nitrictech/go-sdk/constants" - v1 "github.com/nitrictech/nitric/core/pkg/proto/storage/v1" -) - -// Storage - Nitric storage API client -type Storage interface { - // Bucket - Get a bucket reference for the provided name - Bucket(name string) Bucket -} - -type storageImpl struct { - storageClient v1.StorageClient -} - -func (s *storageImpl) Bucket(name string) Bucket { - return &bucketImpl{ - storageClient: s.storageClient, - name: name, - } -} - -// New - Create a new Storage client with default options -func New() (Storage, error) { - ctx, _ := context.WithTimeout(context.Background(), constants.NitricDialTimeout()) - - conn, err := grpc.DialContext( - ctx, - constants.NitricAddress(), - constants.DefaultOptions()..., - ) - if err != nil { - return nil, errors.NewWithCause( - codes.Unavailable, - "Storage.New: Unable to reach StorageServiceServer", - err, - ) - } - - sClient := v1.NewStorageClient(conn) - - return &storageImpl{ - storageClient: sClient, - }, nil -} diff --git a/api/storage/storage_test.go b/api/storage/storage_test.go deleted file mode 100644 index 0be0c87..0000000 --- a/api/storage/storage_test.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package storage - -import ( - "os" - - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - mock_v1 "github.com/nitrictech/go-sdk/mocks" -) - -var _ = Describe("Storage API", func() { - var ( - ctrl *gomock.Controller - mockStorage *mock_v1.MockStorageClient - s Storage - ) - - BeforeEach(func() { - ctrl = gomock.NewController(GinkgoT()) - mockStorage = mock_v1.NewMockStorageClient(ctrl) - - s = &storageImpl{ - storageClient: mockStorage, - } - }) - - AfterEach(func() { - ctrl.Finish() - }) - - Describe("Bucket()", func() { - var bucketName string - var bucketI *bucketImpl - var ok bool - - When("creating a new Bucket reference", func() { - BeforeEach(func() { - bucketName = "test-bucket" - bucket := s.Bucket(bucketName) - bucketI, ok = bucket.(*bucketImpl) - }) - - It("should return a bucketImpl instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should have the provied bucket name", func() { - Expect(bucketI.name).To(Equal(bucketName)) - }) - - It("should share the storage clients gRPC client", func() { - Expect(bucketI.storageClient).To(Equal(mockStorage)) - }) - }) - }) - - Describe("New()", func() { - Context("constructing a new storage client", func() { - When("the gRPC connection is unavailable", func() { - BeforeEach(func() { - os.Setenv("NITRIC_SERVICE_DIAL_TIMEOUT", "10") - }) - AfterEach(func() { - os.Unsetenv("NITRIC_SERVICE_DIAL_TIMEOUT") - }) - - s, err := New() - - It("should return an error", func() { - Expect(err).To(HaveOccurred()) - - By("not returning a storage client") - Expect(s).To(BeNil()) - }) - }) - - PWhen("constructing a new storage client without dial blocking", func() { - // TODO: Mock an available server to connect to - }) - }) - }) -}) diff --git a/api/topics/topics.go b/api/topics/topics.go deleted file mode 100644 index ea9b379..0000000 --- a/api/topics/topics.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package topics - -import ( - "context" - - "google.golang.org/grpc" - - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" - "github.com/nitrictech/go-sdk/constants" - v1 "github.com/nitrictech/nitric/core/pkg/proto/topics/v1" -) - -// Topics -type Topics interface { - // Topic - Retrieve a Topic reference - Topic(name string) Topic -} - -type topicsImpl struct { - topicClient v1.TopicsClient -} - -func (s *topicsImpl) Topic(name string) Topic { - // Just return the straight topic reference - // we can fail if the topic does not exist - return &topicImpl{ - name: name, - topicClient: s.topicClient, - } -} - -// New - Construct a new Eventing Client with default options -func New() (Topics, error) { - ctx, _ := context.WithTimeout(context.Background(), constants.NitricDialTimeout()) - - conn, err := grpc.DialContext( - ctx, - constants.NitricAddress(), - constants.DefaultOptions()..., - ) - if err != nil { - return nil, errors.NewWithCause(codes.Unavailable, "Unable to dial Events service", err) - } - - tc := v1.NewTopicsClient(conn) - - return &topicsImpl{ - topicClient: tc, - }, nil -} diff --git a/api/topics/topics_test.go b/api/topics/topics_test.go deleted file mode 100644 index 428c313..0000000 --- a/api/topics/topics_test.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package topics - -import ( - "os" - - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - mock_v1 "github.com/nitrictech/go-sdk/mocks" -) - -var _ = Describe("Topics API", func() { - var ( - ctrl *gomock.Controller - mockTopics *mock_v1.MockTopicsClient - ts Topics - ) - - BeforeEach(func() { - ctrl = gomock.NewController(GinkgoT()) - mockTopics = mock_v1.NewMockTopicsClient(ctrl) - - ts = &topicsImpl{ - topicClient: mockTopics, - } - }) - - AfterEach(func() { - ctrl.Finish() - }) - - Describe("Topic()", func() { - var topicName string - var topicI *topicImpl - var ok bool - - When("creating a new Topic reference", func() { - BeforeEach(func() { - topicName = "test-topic" - topic := ts.Topic(topicName) - topicI, ok = topic.(*topicImpl) - }) - - It("should return a topicImpl instance", func() { - Expect(ok).To(BeTrue()) - }) - - It("should have the provied topic name", func() { - Expect(topicI.name).To(Equal(topicName)) - }) - - It("should share the storage clients gRPC client", func() { - Expect(topicI.topicClient).To(Equal(mockTopics)) - }) - }) - }) - - Describe("New()", func() { - Context("constructing a new topics client", func() { - When("the gRPC connection is unavailable", func() { - BeforeEach(func() { - os.Setenv("NITRIC_SERVICE_DIAL_TIMEOUT", "10") - }) - AfterEach(func() { - os.Unsetenv("NITRIC_SERVICE_DIAL_TIMEOUT") - }) - - ts, err := New() - - It("should return an error", func() { - Expect(err).To(HaveOccurred()) - - By("not returning a topics client") - Expect(ts).To(BeNil()) - }) - }) - - PWhen("constructing a new topics client without dial blocking", func() { - // TODO: Mock an available server to connect to - }) - }) - }) -}) diff --git a/constants/grpc.go b/constants/grpc.go index 353c136..afa6aa7 100644 --- a/constants/grpc.go +++ b/constants/grpc.go @@ -22,8 +22,6 @@ import ( // DefaultOptions - Provides option defaults for creating a gRPC service connection with the Nitric Membrane func DefaultOptions() []grpc.DialOption { return []grpc.DialOption{ - // TODO: Look at authentication config with membrane - grpc.WithBlock(), grpc.WithTransportCredentials(insecure.NewCredentials()), } } diff --git a/go.mod b/go.mod index 6127b70..bef6532 100644 --- a/go.mod +++ b/go.mod @@ -1,33 +1,32 @@ module github.com/nitrictech/go-sdk -go 1.21 +go 1.22.1 -toolchain go1.21.4 +toolchain go1.23.0 require ( github.com/golang/mock v1.7.0-rc.1 - github.com/golang/protobuf v1.5.3 - github.com/golangci/golangci-lint v1.56.1 + github.com/golang/protobuf v1.5.4 + github.com/golangci/golangci-lint v1.61.0 github.com/google/addlicense v1.1.1 github.com/missionMeteora/toolkit v0.0.0-20170713173850-88364e3ef8cc - github.com/nitrictech/nitric/core v0.0.0-20240501153359-997c6077b84f + github.com/nitrictech/nitric/core v0.0.0-20240915234849-42c1e482ddab github.com/nitrictech/protoutils v0.0.0-20220321044654-02667a814cdf github.com/onsi/ginkgo v1.16.5 - github.com/onsi/gomega v1.28.1 + github.com/onsi/gomega v1.34.2 github.com/uw-labs/lichen v0.1.7 - google.golang.org/grpc v1.59.0 - google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0 + google.golang.org/grpc v1.66.0 + google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 ) require ( 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect 4d63.com/gochecknoglobals v0.2.1 // indirect - github.com/Abirdcfly/dupword v0.0.13 // indirect - github.com/Antonboom/errname v0.1.12 // indirect - github.com/Antonboom/nilnil v0.1.7 // indirect - github.com/BurntSushi/toml v1.3.2 // indirect + github.com/Abirdcfly/dupword v0.1.1 // indirect + github.com/Antonboom/errname v0.1.13 // indirect + github.com/Antonboom/nilnil v0.1.9 // indirect + github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect github.com/Djarvur/go-err113 v0.1.0 // indirect - github.com/Masterminds/semver v1.5.0 // indirect github.com/alexkohler/prealloc v1.0.0 // indirect github.com/alingse/asasalint v0.0.11 // indirect github.com/ashanbrown/forbidigo v1.6.0 // indirect @@ -39,44 +38,38 @@ require ( github.com/breml/bidichk v0.2.7 // indirect github.com/breml/errchkjson v0.3.6 // indirect github.com/butuzov/ireturn v0.3.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charithe/durationcheck v0.0.10 // indirect github.com/chavacava/garif v0.1.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/curioswitch/go-reassign v0.2.0 // indirect - github.com/daixiang0/gci v0.12.1 // indirect + github.com/daixiang0/gci v0.13.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/denis-tingaikin/go-header v0.4.3 // indirect - github.com/esimonov/ifshort v1.0.4 // indirect + github.com/denis-tingaikin/go-header v0.5.0 // indirect github.com/ettle/strcase v0.2.0 // indirect - github.com/fatih/color v1.16.0 // indirect + github.com/fatih/color v1.17.0 // indirect github.com/fatih/structtag v1.2.0 // indirect - github.com/firefart/nonamedreturns v1.0.4 // indirect + github.com/firefart/nonamedreturns v1.0.5 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect - github.com/go-critic/go-critic v0.11.0 // indirect + github.com/go-critic/go-critic v0.11.4 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-toolsmith/astcast v1.1.0 // indirect github.com/go-toolsmith/astcopy v1.1.0 // indirect - github.com/go-toolsmith/astequal v1.1.0 // indirect + github.com/go-toolsmith/astequal v1.2.0 // indirect github.com/go-toolsmith/astfmt v1.1.0 // indirect github.com/go-toolsmith/astp v1.1.0 // indirect github.com/go-toolsmith/strparse v1.1.0 // indirect github.com/go-toolsmith/typep v1.1.0 // indirect github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect github.com/gobwas/glob v0.2.3 // indirect - github.com/gofrs/flock v0.8.1 // indirect - github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect + github.com/gofrs/flock v0.12.1 // indirect github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect - github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe // indirect - github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e // indirect - github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect - github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect - github.com/golangci/misspell v0.4.1 // indirect - github.com/golangci/revgrep v0.5.2 // indirect - github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect + github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 // indirect + github.com/golangci/misspell v0.6.0 // indirect + github.com/golangci/revgrep v0.5.3 // indirect + github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/gordonklaus/ineffassign v0.1.0 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect github.com/gostaticanalysis/comment v1.4.2 // indirect @@ -84,23 +77,22 @@ require ( github.com/gostaticanalysis/nilerr v0.1.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jgautheron/goconst v1.7.0 // indirect + github.com/jgautheron/goconst v1.7.1 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect github.com/julz/importas v0.1.0 // indirect github.com/kisielk/errcheck v1.7.0 // indirect - github.com/kisielk/gotool v1.0.0 // indirect - github.com/kkHAIKE/contextcheck v1.1.4 // indirect + github.com/kkHAIKE/contextcheck v1.1.5 // indirect github.com/kulti/thelper v0.6.3 // indirect - github.com/kunwardeep/paralleltest v1.0.9 // indirect + github.com/kunwardeep/paralleltest v1.0.10 // indirect github.com/kyoh86/exportloopref v0.1.11 // indirect - github.com/ldez/gomoddirectives v0.2.3 // indirect + github.com/ldez/gomoddirectives v0.2.4 // indirect github.com/ldez/tagliatelle v0.5.0 // indirect - github.com/leonklingele/grouper v1.1.1 // indirect + github.com/leonklingele/grouper v1.1.2 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lufeee/execinquery v1.2.1 // indirect github.com/magiconair/properties v1.8.6 // indirect @@ -110,118 +102,123 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect - github.com/mbilski/exhaustivestruct v1.2.0 // indirect - github.com/mgechev/revive v1.3.7 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mgechev/revive v1.3.9 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/moricho/tparallel v0.3.1 // indirect + github.com/moricho/tparallel v0.3.2 // indirect github.com/muesli/termenv v0.15.2 // indirect github.com/nakabonne/nestif v0.3.1 // indirect github.com/nishanths/exhaustive v0.12.0 // indirect github.com/nishanths/predeclared v0.2.2 // indirect - github.com/nunnatsa/ginkgolinter v0.15.2 // indirect - github.com/nxadm/tail v1.4.8 // indirect + github.com/nunnatsa/ginkgolinter v0.16.2 // indirect + github.com/nxadm/tail v1.4.11 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.5 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/polyfloyd/go-errorlint v1.4.8 // indirect + github.com/polyfloyd/go-errorlint v1.6.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect - github.com/quasilyte/go-ruleguard v0.4.0 // indirect + github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/ryancurrah/gomodguard v1.3.0 // indirect + github.com/ryancurrah/gomodguard v1.3.5 // indirect github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect - github.com/sashamelentyev/usestdlibvars v1.24.0 // indirect - github.com/securego/gosec/v2 v2.18.2 // indirect - github.com/sergi/go-diff v1.3.1 // indirect + github.com/sashamelentyev/usestdlibvars v1.27.0 // indirect + github.com/securego/gosec/v2 v2.21.2 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sivchari/containedctx v1.0.3 // indirect - github.com/sivchari/nosnakecase v1.7.0 // indirect - github.com/sivchari/tenv v1.7.1 // indirect + github.com/sivchari/tenv v1.10.0 // indirect github.com/sonatard/noctx v0.0.2 // indirect github.com/sourcegraph/go-diff v0.7.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/cobra v1.7.0 // indirect + github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.14.0 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect - github.com/stretchr/objx v0.5.0 // indirect - github.com/stretchr/testify v1.8.4 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/testify v1.9.0 // indirect github.com/subosito/gotenv v1.4.1 // indirect - github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect github.com/tdakkota/asciicheck v0.2.0 // indirect - github.com/tetafro/godot v1.4.16 // indirect + github.com/tetafro/godot v1.4.17 // indirect github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect github.com/timonwong/loggercheck v0.9.4 // indirect - github.com/tomarrell/wrapcheck/v2 v2.8.1 // indirect + github.com/tomarrell/wrapcheck/v2 v2.9.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect github.com/ultraware/funlen v0.1.0 // indirect - github.com/ultraware/whitespace v0.1.0 // indirect - github.com/uudashr/gocognit v1.1.2 // indirect + github.com/ultraware/whitespace v0.1.1 // indirect + github.com/uudashr/gocognit v1.1.3 // indirect github.com/yagipy/maintidx v1.0.0 // indirect - github.com/yeya24/promlinter v0.2.0 // indirect - gitlab.com/bosi/decorder v0.4.1 // indirect + github.com/yeya24/promlinter v0.3.0 // indirect + gitlab.com/bosi/decorder v0.4.2 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect - golang.org/x/exp/typeparams v0.0.0-20231219180239-dc181d75b848 // indirect - golang.org/x/mod v0.15.0 // indirect - golang.org/x/net v0.20.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.17.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect + golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/tools v0.24.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/protobuf v1.34.2 gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - honnef.co/go/tools v0.4.6 // indirect - mvdan.cc/gofumpt v0.6.0 // indirect - mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect - mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect - mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14 // indirect + honnef.co/go/tools v0.5.1 // indirect + mvdan.cc/gofumpt v0.7.0 // indirect + mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect ) replace github.com/google/licenseclassifier => github.com/google/licenseclassifier v0.0.0-20201113175434-78a70215ca36 require ( - github.com/4meepo/tagalign v1.3.3 // indirect - github.com/Antonboom/testifylint v1.1.1 // indirect - github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0 // indirect + github.com/4meepo/tagalign v1.3.4 // indirect + github.com/Antonboom/testifylint v1.4.3 // indirect + github.com/Crocmagnon/fatcontext v0.5.2 // indirect + github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect + github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect github.com/alecthomas/go-check-sumtype v0.1.4 // indirect - github.com/alexkohler/nakedret/v2 v2.0.2 // indirect + github.com/alexkohler/nakedret/v2 v2.0.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/bombsimon/wsl/v4 v4.2.0 // indirect - github.com/butuzov/mirror v1.1.0 // indirect - github.com/catenacyber/perfsprint v0.6.0 // indirect - github.com/ccojocar/zxcvbn-go v1.0.1 // indirect - github.com/ghostiam/protogetter v0.3.4 // indirect - github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect + github.com/bombsimon/wsl/v4 v4.4.1 // indirect + github.com/butuzov/mirror v1.2.0 // indirect + github.com/catenacyber/perfsprint v0.7.1 // indirect + github.com/ccojocar/zxcvbn-go v1.0.2 // indirect + github.com/ckaznocha/intrange v0.2.0 // indirect + github.com/ghostiam/protogetter v0.3.6 // indirect + github.com/go-viper/mapstructure/v2 v2.1.0 // indirect + github.com/golangci/modinfo v0.3.4 // indirect + github.com/golangci/plugin-module-register v0.1.1 // indirect github.com/google/licenseclassifier v0.0.0-20220326190949-7c62d6fe8d3a // indirect - github.com/jjti/go-spancheck v0.5.2 // indirect + github.com/jjti/go-spancheck v0.6.2 // indirect + github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect + github.com/lasiar/canonicalheader v1.1.1 // indirect github.com/macabu/inamedparam v0.1.3 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect github.com/urfave/cli/v2 v2.6.0 // indirect github.com/xen0n/gosmopolitan v1.2.2 // indirect github.com/ykadowak/zerologlint v0.1.5 // indirect - go-simpler.org/musttag v0.8.0 // indirect - go-simpler.org/sloglint v0.4.0 // indirect + go-simpler.org/musttag v0.12.2 // indirect + go-simpler.org/sloglint v0.7.2 // indirect + go.uber.org/automaxprocs v1.5.3 // indirect go.uber.org/goleak v1.2.1 // indirect ) diff --git a/go.sum b/go.sum index 650b475..8da0a9f 100644 --- a/go.sum +++ b/go.sum @@ -35,26 +35,28 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/4meepo/tagalign v1.3.3 h1:ZsOxcwGD/jP4U/aw7qeWu58i7dwYemfy5Y+IF1ACoNw= -github.com/4meepo/tagalign v1.3.3/go.mod h1:Q9c1rYMZJc9dPRkbQPpcBNCLEmY2njbAsXhQOZFE2dE= -github.com/Abirdcfly/dupword v0.0.13 h1:SMS17YXypwP000fA7Lr+kfyBQyW14tTT+nRv9ASwUUo= -github.com/Abirdcfly/dupword v0.0.13/go.mod h1:Ut6Ue2KgF/kCOawpW4LnExT+xZLQviJPE4klBPMK/5Y= -github.com/Antonboom/errname v0.1.12 h1:oh9ak2zUtsLp5oaEd/erjB4GPu9w19NyoIskZClDcQY= -github.com/Antonboom/errname v0.1.12/go.mod h1:bK7todrzvlaZoQagP1orKzWXv59X/x0W0Io2XT1Ssro= -github.com/Antonboom/nilnil v0.1.7 h1:ofgL+BA7vlA1K2wNQOsHzLJ2Pw5B5DpWRLdDAVvvTow= -github.com/Antonboom/nilnil v0.1.7/go.mod h1:TP+ScQWVEq0eSIxqU8CbdT5DFWoHp0MbP+KMUO1BKYQ= -github.com/Antonboom/testifylint v1.1.1 h1:xCxYDNOBLImTKjBKPGtx1cHkTSywDAn76mYHTwH5lG8= -github.com/Antonboom/testifylint v1.1.1/go.mod h1:9PFi+vWa8zzl4/B/kqmFJcw85ZUv8ReyBzuQCd30+WI= +github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8= +github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0= +github.com/Abirdcfly/dupword v0.1.1 h1:Bsxe0fIw6OwBtXMIncaTxCLHYO5BB+3mcsR5E8VXloY= +github.com/Abirdcfly/dupword v0.1.1/go.mod h1:B49AcJdTYYkpd4HjgAcutNGG9HZ2JWwKunH9Y2BA6sM= +github.com/Antonboom/errname v0.1.13 h1:JHICqsewj/fNckzrfVSe+T33svwQxmjC+1ntDsHOVvM= +github.com/Antonboom/errname v0.1.13/go.mod h1:uWyefRYRN54lBg6HseYCFhs6Qjcy41Y3Jl/dVhA87Ns= +github.com/Antonboom/nilnil v0.1.9 h1:eKFMejSxPSA9eLSensFmjW2XTgTwJMjZ8hUHtV4s/SQ= +github.com/Antonboom/nilnil v0.1.9/go.mod h1:iGe2rYwCq5/Me1khrysB4nwI7swQvjclR8/YRPl5ihQ= +github.com/Antonboom/testifylint v1.4.3 h1:ohMt6AHuHgttaQ1xb6SSnxCeK4/rnK7KKzbvs7DmEck= +github.com/Antonboom/testifylint v1.4.3/go.mod h1:+8Q9+AOLsz5ZiQiiYujJKs9mNz398+M6UgslP4qgJLA= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs= +github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Crocmagnon/fatcontext v0.5.2 h1:vhSEg8Gqng8awhPju2w7MKHqMlg4/NI+gSDHtR3xgwA= +github.com/Crocmagnon/fatcontext v0.5.2/go.mod h1:87XhRMaInHP44Q7Tlc7jkgKKB7kZAOPiDkFMdKCC+74= github.com/Djarvur/go-err113 v0.1.0 h1:uCRZZOdMQ0TZPHYTdYpoC0bLYJKPEHPUJ8MeAa51lNU= github.com/Djarvur/go-err113 v0.1.0/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= -github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0 h1:sATXp1x6/axKxz2Gjxv8MALP0bXaNRfQinEwyfMcx8c= -github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0/go.mod h1:Nl76DrGNJTA1KJ0LePKBw/vznBX1EHbAZX8mwjR82nI= -github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC23cV0kEsN1MVMNqeOW43cU= +github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0/go.mod h1:ONJg5sxcbsdQQ4pOW8TGdTidT2TMAUy/2Xhr8mrYaao= +github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA= github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ= github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= @@ -68,8 +70,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alexkohler/nakedret/v2 v2.0.2 h1:qnXuZNvv3/AxkAb22q/sEsEpcA99YxLFACDtEw9TPxE= -github.com/alexkohler/nakedret/v2 v2.0.2/go.mod h1:2b8Gkk0GsOrqQv/gPWjNLDSKwG8I5moSXG1K4VIBcTQ= +github.com/alexkohler/nakedret/v2 v2.0.4 h1:yZuKmjqGi0pSmjGpOC016LtPJysIL0WEUiaXW5SUnNg= +github.com/alexkohler/nakedret/v2 v2.0.4/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU= github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= @@ -92,25 +94,25 @@ github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= github.com/bmatcuk/doublestar/v4 v4.0.2 h1:X0krlUVAVmtr2cRoTqR8aDMrDqnB36ht8wpWTiQ3jsA= github.com/bmatcuk/doublestar/v4 v4.0.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/bombsimon/wsl/v4 v4.2.0 h1:dKK3o/Hk2aIt6t72CWg02ham2P5lnH9MBSW6cTU9xxU= -github.com/bombsimon/wsl/v4 v4.2.0/go.mod h1:1zaTbf/7ywOQtMdoUdTF2X1fbbBLiBUkajyuFAanT28= +github.com/bombsimon/wsl/v4 v4.4.1 h1:jfUaCkN+aUpobrMO24zwyAMwMAV5eSziCkOKEauOLdw= +github.com/bombsimon/wsl/v4 v4.4.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo= github.com/breml/bidichk v0.2.7 h1:dAkKQPLl/Qrk7hnP6P+E0xOodrq8Us7+U0o4UBOAlQY= github.com/breml/bidichk v0.2.7/go.mod h1:YodjipAGI9fGcYM7II6wFvGhdMYsC5pHDlGzqvEW3tQ= github.com/breml/errchkjson v0.3.6 h1:VLhVkqSBH96AvXEyclMR37rZslRrY2kcyq+31HCsVrA= github.com/breml/errchkjson v0.3.6/go.mod h1:jhSDoFheAF2RSDOlCfhHO9KqhZgAYLyvHe7bRCX8f/U= github.com/butuzov/ireturn v0.3.0 h1:hTjMqWw3y5JC3kpnC5vXmFJAWI/m31jaCYQqzkS6PL0= github.com/butuzov/ireturn v0.3.0/go.mod h1:A09nIiwiqzN/IoVo9ogpa0Hzi9fex1kd9PSD6edP5ZA= -github.com/butuzov/mirror v1.1.0 h1:ZqX54gBVMXu78QLoiqdwpl2mgmoOJTk7s4p4o+0avZI= -github.com/butuzov/mirror v1.1.0/go.mod h1:8Q0BdQU6rC6WILDiBM60DBfvV78OLJmMmixe7GF45AE= -github.com/catenacyber/perfsprint v0.6.0 h1:VSv95RRkk5+BxrU/YTPcnxuMEWar1iMK5Vyh3fWcBfs= -github.com/catenacyber/perfsprint v0.6.0/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50= -github.com/ccojocar/zxcvbn-go v1.0.1 h1:+sxrANSCj6CdadkcMnvde/GWU1vZiiXRbqYSCalV4/4= -github.com/ccojocar/zxcvbn-go v1.0.1/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= +github.com/butuzov/mirror v1.2.0 h1:9YVK1qIjNspaqWutSv8gsge2e/Xpq1eqEkslEUHy5cs= +github.com/butuzov/mirror v1.2.0/go.mod h1:DqZZDtzm42wIAIyHXeN8W/qb1EPlb9Qn/if9icBOpdQ= +github.com/catenacyber/perfsprint v0.7.1 h1:PGW5G/Kxn+YrN04cRAZKC+ZuvlVwolYMrIyyTJ/rMmc= +github.com/catenacyber/perfsprint v0.7.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50= +github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg= +github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4= github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc= @@ -118,45 +120,45 @@ github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+U github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/ckaznocha/intrange v0.2.0 h1:FykcZuJ8BD7oX93YbO1UY9oZtkRbp+1/kJcDjkefYLs= +github.com/ckaznocha/intrange v0.2.0/go.mod h1:r5I7nUlAAG56xmkOpw4XVr16BXhwYTUdcuRFeevn1oE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= -github.com/daixiang0/gci v0.12.1 h1:ugsG+KRYny1VK4oqrX4Vtj70bo4akYKa0tgT1DXMYiY= -github.com/daixiang0/gci v0.12.1/go.mod h1:xtHP9N7AHdNvtRNfcx9gwTDfw7FRJx4bZUsiEfiNNAI= +github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c= +github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denis-tingaikin/go-header v0.4.3 h1:tEaZKAlqql6SKCY++utLmkPLd6K8IBM20Ha7UVm+mtU= -github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= +github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= +github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStBA= -github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y= -github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIga8MAO/xbKdcVsGI= -github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= -github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA= +github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/ghostiam/protogetter v0.3.4 h1:5SZ+lZSNmNkSbGVSF9hUHhv/b7ELF9Rwchoq7btYo6c= -github.com/ghostiam/protogetter v0.3.4/go.mod h1:A0JgIhs0fgVnotGinjQiKaFVG3waItLJNwPmcMzDnvk= -github.com/go-critic/go-critic v0.11.0 h1:mARtIFX7jPtJ3SzxO9Isa5T2jd2dZxFmQHK3yNf0wrE= -github.com/go-critic/go-critic v0.11.0/go.mod h1:Cz6lr1PlkIu/0Y0U9KqJgcIJJECAF8mEwmzVjKnhbfI= +github.com/ghostiam/protogetter v0.3.6 h1:R7qEWaSgFCsy20yYHNIJsU9ZOb8TziSRRxuAOTVKeOk= +github.com/ghostiam/protogetter v0.3.6/go.mod h1:7lpeDnEJ1ZjL/YtyoN99ljO4z0pd3H0d18/t2dPBxHw= +github.com/go-critic/go-critic v0.11.4 h1:O7kGOCx0NDIni4czrkRIXTnit0mkyKOCePh3My6OyEU= +github.com/go-critic/go-critic v0.11.4/go.mod h1:2QAdo4iuLik5S9YG0rT4wcZ8QxwHYkrr6/2MWAiv/vc= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -168,19 +170,24 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= +github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s= github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= -github.com/go-toolsmith/astequal v1.1.0 h1:kHKm1AWqClYn15R0K1KKE4RG614D46n+nqUQ06E1dTw= github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= +github.com/go-toolsmith/astequal v1.2.0 h1:3Fs3CYZ1k9Vo4FzFhwwewC3CHISHDnVUPC4x0bI2+Cw= +github.com/go-toolsmith/astequal v1.2.0/go.mod h1:c8NZ3+kSFtFY/8lPso4v8LuJjdJiUFVnSuU3s0qrrDY= github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco= github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA= @@ -192,14 +199,14 @@ github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQi github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= -github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c= -github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= +github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= -github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= +github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -230,28 +237,24 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0= -github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= -github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe h1:6RGUuS7EGotKx6J5HIP8ZtyMdiDscjMLfRBSPuzVVeo= -github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= -github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e h1:ULcKCDV1LOZPFxGZaA6TlQbiM3J2GCPnkx/bGF6sX/g= -github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e/go.mod h1:Pm5KhLPA8gSnQwrQ6ukebRcapGb/BG9iUkdaiCcGHJM= -github.com/golangci/golangci-lint v1.56.1 h1:vR6rJpjE1w6pRp2EkVeCAbISyUIl6c7OO/hrEtGK1yo= -github.com/golangci/golangci-lint v1.56.1/go.mod h1:sOHqnOxdEZ0u9JYrDuofOaIyO0jRgT8Y6nWfzuoSv0Y= -github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA= -github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= -github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA= -github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= -github.com/golangci/misspell v0.4.1 h1:+y73iSicVy2PqyX7kmUefHusENlrP9YwuHZHPLGQj/g= -github.com/golangci/misspell v0.4.1/go.mod h1:9mAN1quEo3DlpbaIKKyEvRxK1pwqR9s/Sea1bJCtlNI= -github.com/golangci/revgrep v0.5.2 h1:EndcWoRhcnfj2NHQ+28hyuXpLMF+dQmCN+YaeeIl4FU= -github.com/golangci/revgrep v0.5.2/go.mod h1:bjAMA+Sh/QUfTDcHzxfyHxr4xKvllVr/0sCv2e7jJHA= -github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys= -github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= +github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 h1:/1322Qns6BtQxUZDTAT4SdcoxknUki7IAoK4SAXr8ME= +github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9/go.mod h1:Oesb/0uFAyWoaw1U1qS5zyjCg5NP9C9iwjnI4tIsXEE= +github.com/golangci/golangci-lint v1.61.0 h1:VvbOLaRVWmyxCnUIMTbf1kDsaJbTzH20FAMXTAlQGu8= +github.com/golangci/golangci-lint v1.61.0/go.mod h1:e4lztIrJJgLPhWvFPDkhiMwEFRrWlmFbrZea3FsJyN8= +github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs= +github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo= +github.com/golangci/modinfo v0.3.4 h1:oU5huX3fbxqQXdfspamej74DFX0kyGLkw1ppvXoJ8GA= +github.com/golangci/modinfo v0.3.4/go.mod h1:wytF1M5xl9u0ij8YSvhkEVPP3M5Mc7XLl1pxH3B2aUM= +github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c= +github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc= +github.com/golangci/revgrep v0.5.3 h1:3tL7c1XBMtWHHqVpS5ChmiAAoe4PF/d5+ULzV9sLAzs= +github.com/golangci/revgrep v0.5.3/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= +github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs= +github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ= github.com/google/addlicense v1.1.1 h1:jpVf9qPbU8rz5MxKo7d+RMcNHkqxi4YJi/laauX4aAE= github.com/google/addlicense v1.1.1/go.mod h1:Sm/DHu7Jk+T5miFHHehdIjbi4M5+dJDRS3Cq0rncIxA= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -282,8 +285,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= +github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= @@ -307,8 +310,8 @@ github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= -github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -317,17 +320,16 @@ github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUq github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jgautheron/goconst v1.7.0 h1:cEqH+YBKLsECnRSd4F4TK5ri8t/aXtt/qoL0Ft252B0= -github.com/jgautheron/goconst v1.7.0/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= +github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= -github.com/jjti/go-spancheck v0.5.2 h1:WXTZG3efY/ji1Vi8mkH+23O3bLeKR6hp3tI3YB7XwKk= -github.com/jjti/go-spancheck v0.5.2/go.mod h1:ARPNI1JRG1V2Rjnd6/2f2NEfghjSVDZGVmruNKlnXU0= +github.com/jjti/go-spancheck v0.6.2 h1:iYtoxqPMzHUPp7St+5yA8+cONdyXD3ug6KK15n7Pklk= +github.com/jjti/go-spancheck v0.6.2/go.mod h1:+X7lvIrR5ZdUTkxFYqzJ0abr8Sb5LOo80uOhWNqIrYA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -339,12 +341,13 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= +github.com/karamaru-alpha/copyloopvar v1.1.0 h1:x7gNyKcC2vRBO1H2Mks5u1VxQtYvFiym7fCjIP8RPos= +github.com/karamaru-alpha/copyloopvar v1.1.0/go.mod h1:u7CIfztblY0jZLOQZgH3oYsJzpC2A7S6u/lfgSXHy0k= github.com/kisielk/errcheck v1.7.0 h1:+SbscKmWJ5mOK/bO1zS60F5I9WwZDWOfRsC4RwfwRV0= github.com/kisielk/errcheck v1.7.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ= -github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkHAIKE/contextcheck v1.1.4 h1:B6zAaLhOEEcjvUgIYEqystmnFk1Oemn8bvJhbt0GMb8= -github.com/kkHAIKE/contextcheck v1.1.4/go.mod h1:1+i/gWqokIa+dm31mqGLZhZJ7Uh44DJGZVmr6QRBNJg= +github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LXxiilg= +github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -357,16 +360,18 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= -github.com/kunwardeep/paralleltest v1.0.9 h1:3Sr2IfFNcsMmlqPk1cjTUbJ4zofKPGyHxenwPebgTug= -github.com/kunwardeep/paralleltest v1.0.9/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= +github.com/kunwardeep/paralleltest v1.0.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs= +github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ= github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA= -github.com/ldez/gomoddirectives v0.2.3 h1:y7MBaisZVDYmKvt9/l1mjNCiSA1BVn34U0ObUcJwlhA= -github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= +github.com/lasiar/canonicalheader v1.1.1 h1:wC+dY9ZfiqiPwAexUApFush/csSPXeIi4QqyxXmng8I= +github.com/lasiar/canonicalheader v1.1.1/go.mod h1:cXkb3Dlk6XXy+8MVQnF23CYKWlyA7kfQhSw2CcZtZb0= +github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJZ3alg= +github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g= github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo= github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= -github.com/leonklingele/grouper v1.1.1 h1:suWXRU57D4/Enn6pXR0QVqqWWrnJ9Osrz+5rjt8ivzU= -github.com/leonklingele/grouper v1.1.1/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= +github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= +github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= @@ -392,12 +397,10 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= -github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo= -github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= -github.com/mgechev/revive v1.3.7 h1:502QY0vQGe9KtYJ9FpxMz9rL+Fc/P13CI5POL4uHCcE= -github.com/mgechev/revive v1.3.7/go.mod h1:RJ16jUbF0OWC3co/+XTxmFNgEpUPwnnA0BRllX2aDNA= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A= +github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU= github.com/missionMeteora/toolkit v0.0.0-20170713173850-88364e3ef8cc h1:/oFlKiuu6L1sIvZ7A363qMhNM+DUQL5WsVe1xIRQnFU= github.com/missionMeteora/toolkit v0.0.0-20170713173850-88364e3ef8cc/go.mod h1:AtX+JBtXbQ+taj82QFzCSgN5EzM4Bi0YRyS+TVbjENs= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -409,8 +412,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/moricho/tparallel v0.3.1 h1:fQKD4U1wRMAYNngDonW5XupoB/ZGJHdpzrWqgyg9krA= -github.com/moricho/tparallel v0.3.1/go.mod h1:leENX2cUv7Sv2qDgdi0D0fCftN8fRC67Bcn8pqzeYNI= +github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI= +github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -421,27 +424,28 @@ github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhK github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= -github.com/nitrictech/nitric/core v0.0.0-20240501153359-997c6077b84f h1:usgb/sRqzHSNcGsC8yIVAmXVdXaE4ZyAwzLzuW5+lag= -github.com/nitrictech/nitric/core v0.0.0-20240501153359-997c6077b84f/go.mod h1:OfaIrPrJJjrFNOOgYbzoBGUblO2DadoXCrloAsUW0H0= +github.com/nitrictech/nitric/core v0.0.0-20240915234849-42c1e482ddab h1:59YTNUa6en385Y21SwMTaixbe31SwgzjkjEhxx0RuwQ= +github.com/nitrictech/nitric/core v0.0.0-20240915234849-42c1e482ddab/go.mod h1:N274XVBjYhGEQoT42baWM6/lETBQYQhqPpqUuk2gmLc= github.com/nitrictech/protoutils v0.0.0-20220321044654-02667a814cdf h1:8MB8W8ylM8sCM2COGfiO39/tB6BTdiawLszaUGCNL5w= github.com/nitrictech/protoutils v0.0.0-20220321044654-02667a814cdf/go.mod h1:b2lzk2a4o1bvSrSCE6yvTldHuXCJymuDVhdMJGOSslw= -github.com/nunnatsa/ginkgolinter v0.15.2 h1:N2ORxUxPU56R9gsfLIlVVvCv/V/VVou5qVI1oBKBNHg= -github.com/nunnatsa/ginkgolinter v0.15.2/go.mod h1:oYxE7dt1vZI8cK2rZOs3RgTaBN2vggkqnENmoJ8kVvc= +github.com/nunnatsa/ginkgolinter v0.16.2 h1:8iLqHIZvN4fTLDC0Ke9tbSZVcyVHoBs0HIbnVSxfHJk= +github.com/nunnatsa/ginkgolinter v0.16.2/go.mod h1:4tWRinDN1FeJgU+iJANW/kz7xKN5nYRAOfJDQUS9dOQ= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= +github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.28.1 h1:MijcGUbfYuznzK/5R4CPNoUP/9Xvuo20sXfEm6XxoTA= -github.com/onsi/gomega v1.28.1/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= +github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= @@ -451,8 +455,8 @@ github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT9 github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= -github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -460,8 +464,10 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polyfloyd/go-errorlint v1.4.8 h1:jiEjKDH33ouFktyez7sckv6pHWif9B7SuS8cutDXFHw= -github.com/polyfloyd/go-errorlint v1.4.8/go.mod h1:NNCxFcFjZcw3xNjVdCchERkEM6Oz7wta2XJVxRftwO4= +github.com/polyfloyd/go-errorlint v1.6.0 h1:tftWV9DE7txiFzPpztTAwyoRLKNj9gpVm2cg8/OwcYY= +github.com/polyfloyd/go-errorlint v1.6.0/go.mod h1:HR7u8wuP1kb1NeN1zqTd1ZMlqUKPPHF+Id4vIPvDqVw= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -473,8 +479,8 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= @@ -488,8 +494,10 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/quasilyte/go-ruleguard v0.4.0 h1:DyM6r+TKL+xbKB4Nm7Afd1IQh9kEUKQs2pboWGKtvQo= -github.com/quasilyte/go-ruleguard v0.4.0/go.mod h1:Eu76Z/R8IXtViWUIHkE3p8gdH3/PKk1eh3YGfaEof10= +github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 h1:+Wl/0aFp0hpuHM3H//KMft64WQ1yX9LdJY64Qm/gFCo= +github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI= +github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= +github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= @@ -504,21 +512,23 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryancurrah/gomodguard v1.3.0 h1:q15RT/pd6UggBXVBuLps8BXRvl5GPBcwVA7BJHMLuTw= -github.com/ryancurrah/gomodguard v1.3.0/go.mod h1:ggBxb3luypPEzqVtq33ee7YSN35V28XeGnid8dnni50= +github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU= +github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE= github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc= github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= -github.com/sashamelentyev/usestdlibvars v1.24.0 h1:MKNzmXtGh5N0y74Z/CIaJh4GlB364l0K1RUT08WSWAc= -github.com/sashamelentyev/usestdlibvars v1.24.0/go.mod h1:9cYkq+gYJ+a5W2RPdhfaSCnTVUC1OQP/bSiiBhq3OZE= -github.com/securego/gosec/v2 v2.18.2 h1:DkDt3wCiOtAHf1XkiXZBhQ6m6mK/b9T/wD257R3/c+I= -github.com/securego/gosec/v2 v2.18.2/go.mod h1:xUuqSF6i0So56Y2wwohWAmB07EdBkUN6crbLlHwbyJs= +github.com/sashamelentyev/usestdlibvars v1.27.0 h1:t/3jZpSXtRPRf2xr0m63i32ZrusyurIGT9E5wAvXQnI= +github.com/sashamelentyev/usestdlibvars v1.27.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8= +github.com/securego/gosec/v2 v2.21.2 h1:deZp5zmYf3TWwU7A7cR2+SolbTpZ3HQiwFqnzQyEl3M= +github.com/securego/gosec/v2 v2.21.2/go.mod h1:au33kg78rNseF5PwPnTWhuYBFf534bvJRvOrgZ/bFzU= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= -github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= @@ -530,10 +540,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= -github.com/sivchari/nosnakecase v1.7.0 h1:7QkpWIRMe8x25gckkFd2A5Pi6Ymo0qgr4JrhGt95do8= -github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY= -github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak= -github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= +github.com/sivchari/tenv v1.10.0 h1:g/hzMA+dBCKqGXgW8AV/1xIWhAvDrx0zFKNR48NFMg0= +github.com/sivchari/tenv v1.10.0/go.mod h1:tdY24masnVoZFxYrHv/nD6Tc8FbkEtAQEEziXpyMgqY= github.com/sonatard/noctx v0.0.2 h1:L7Dz4De2zDQhW8S0t+KUjY0MAQJd6SgVwhzNIc4ok00= github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo= github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= @@ -542,8 +550,8 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -557,8 +565,9 @@ github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8L github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -567,44 +576,43 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c h1:+aPplBwWcHBo6q9xrfWdMrT9o4kltkmmvpemgIjep/8= -github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk= github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM= github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg= github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= -github.com/tetafro/godot v1.4.16 h1:4ChfhveiNLk4NveAZ9Pu2AN8QZ2nkUGFuadM9lrr5D0= -github.com/tetafro/godot v1.4.16/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= +github.com/tetafro/godot v1.4.17 h1:pGzu+Ye7ZUEFx7LHU0dAKmCOXWsPjl7qA6iMGndsjPs= +github.com/tetafro/godot v1.4.17/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M= github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= github.com/timonwong/loggercheck v0.9.4 h1:HKKhqrjcVj8sxL7K77beXh0adEm6DLjV/QOGeMXEVi4= github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg= -github.com/tomarrell/wrapcheck/v2 v2.8.1 h1:HxSqDSN0sAt0yJYsrcYVoEeyM4aI9yAm3KQpIXDJRhQ= -github.com/tomarrell/wrapcheck/v2 v2.8.1/go.mod h1:/n2Q3NZ4XFT50ho6Hbxg+RV1uyo2Uow/Vdm9NQcl5SE= +github.com/tomarrell/wrapcheck/v2 v2.9.0 h1:801U2YCAjLhdN8zhZ/7tdjB3EnAoRlJHt/s+9hijLQ4= +github.com/tomarrell/wrapcheck/v2 v2.9.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo= github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81vI= github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4= -github.com/ultraware/whitespace v0.1.0 h1:O1HKYoh0kIeqE8sFqZf1o0qbORXUCOQFrlaQyZsczZw= -github.com/ultraware/whitespace v0.1.0/go.mod h1:/se4r3beMFNmewJ4Xmz0nMQ941GJt+qmSHGP9emHYe0= +github.com/ultraware/whitespace v0.1.1 h1:bTPOGejYFulW3PkcrqkeQwOd6NKOOXvmGD9bo/Gk8VQ= +github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= github.com/urfave/cli/v2 v2.6.0 h1:yj2Drkflh8X/zUrkWlWlUjZYHyWN7WMmpVxyxXIUyv8= github.com/urfave/cli/v2 v2.6.0/go.mod h1:oDzoM7pVwz6wHn5ogWgFUU1s4VJayeQS+aEZDqXIEJs= -github.com/uudashr/gocognit v1.1.2 h1:l6BAEKJqQH2UpKAPKdMfZf5kE4W/2xk8pfU1OVLvniI= -github.com/uudashr/gocognit v1.1.2/go.mod h1:aAVdLURqcanke8h3vg35BC++eseDm66Z7KmchI5et4k= +github.com/uudashr/gocognit v1.1.3 h1:l+a111VcDbKfynh+airAy/DJQKaXh2m9vkoysMPSZyM= +github.com/uudashr/gocognit v1.1.3/go.mod h1:aKH8/e8xbTRBwjbCkwZ8qt4l2EpKXl31KMHgSS+lZ2U= github.com/uw-labs/lichen v0.1.7 h1:SDNE3kThhhtP70XfLN/C2bqaT9Epefg1i10lhWYIG4g= github.com/uw-labs/lichen v0.1.7/go.mod h1:bvEgoBeVZGhzstRxPEpEwM4TGT6AJZ6GA29a4FuLxYw= github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU= github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg= github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= -github.com/yeya24/promlinter v0.2.0 h1:xFKDQ82orCU5jQujdaD8stOHiv8UN68BSdn2a8u8Y3o= -github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA= +github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs= +github.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+YcPQN+mW4= github.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw= github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -614,14 +622,14 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -gitlab.com/bosi/decorder v0.4.1 h1:VdsdfxhstabyhZovHafFw+9eJ6eU0d2CkFNJcZz/NU4= -gitlab.com/bosi/decorder v0.4.1/go.mod h1:jecSqWUew6Yle1pCr2eLWTensJMmsxHsBwt+PVbkAqA= -go-simpler.org/assert v0.7.0 h1:OzWWZqfNxt8cLS+MlUp6Tgk1HjPkmgdKBq9qvy8lZsA= -go-simpler.org/assert v0.7.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= -go-simpler.org/musttag v0.8.0 h1:DR4UTgetNNhPRNo02rkK1hwDTRzAPotN+ZqYpdtEwWc= -go-simpler.org/musttag v0.8.0/go.mod h1:fiNdCkXt2S6je9Eblma3okjnlva9NT1Eg/WUt19rWu8= -go-simpler.org/sloglint v0.4.0 h1:UVJuUJo63iNQNFEOtZ6o1xAgagVg/giVLLvG9nNLobI= -go-simpler.org/sloglint v0.4.0/go.mod h1:v6zJ++j/thFPhefs2wEXoCKwT10yo5nkBDYRCXyqgNQ= +gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= +gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= +go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= +go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= +go-simpler.org/musttag v0.12.2 h1:J7lRc2ysXOq7eM8rwaTYnNrHd5JwjppzB6mScysB2Cs= +go-simpler.org/musttag v0.12.2/go.mod h1:uN1DVIasMTQKk6XSik7yrJoEysGtR2GRqvWnI9S7TYM= +go-simpler.org/sloglint v0.7.2 h1:Wc9Em/Zeuu7JYpl+oKoYOsQSy2X560aVueCW/m6IijY= +go-simpler.org/sloglint v0.7.2/go.mod h1:US+9C80ppl7VsThQclkM7BkCHQAzuz8kHLsW3ppuluo= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -630,6 +638,8 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= +go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= @@ -654,12 +664,12 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM= -golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk= +golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20231219180239-dc181d75b848 h1:UhRVJ0i7bF9n/Hd8YjW3eKjlPVBHzbQdxrBgjbSKl64= -golang.org/x/exp/typeparams v0.0.0-20231219180239-dc181d75b848/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8= +golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -688,8 +698,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -732,8 +742,8 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -754,8 +764,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -806,7 +816,6 @@ golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -816,8 +825,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -834,8 +843,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -886,7 +895,6 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= @@ -897,14 +905,13 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -960,8 +967,8 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -974,10 +981,10 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0 h1:TLkBREm4nIsEcexnCjgQd5GQWaHcqMzwQV0TX9pq8S0= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0/go.mod h1:DNq5QpG7LJqD2AamLZ7zvKE0DEpVl2BSEVjFycAAjRY= +google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= +google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -990,9 +997,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1023,16 +1029,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.4.6 h1:oFEHCKeID7to/3autwsWfnuv69j3NsfcXbvJKuIcep8= -honnef.co/go/tools v0.4.6/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0= -mvdan.cc/gofumpt v0.6.0 h1:G3QvahNDmpD+Aek/bNOLrFR2XC6ZAdo62dZu65gmwGo= -mvdan.cc/gofumpt v0.6.0/go.mod h1:4L0wf+kgIPZtcCWXynNS2e6bhmj73umwnuXSZarixzA= -mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= -mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= -mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo= -mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= -mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14 h1:zCr3iRRgdk5eIikZNDphGcM6KGVTx3Yu+/Uu9Es254w= -mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14/go.mod h1:ZzZjEpJDOmx8TdVU6umamY3Xy0UAQUI2DHbf05USVbI= +honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I= +honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs= +mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU= +mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo= +mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U= +mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/handler/blob_event.go b/handler/blob_event.go deleted file mode 100644 index 497bb33..0000000 --- a/handler/blob_event.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package handler - -type ( - BlobEventHandler = func(*BlobEventContext) (*BlobEventContext, error) - BlobEventMiddleware = func(*BlobEventContext, BlobEventHandler) (*BlobEventContext, error) -) - -func BlobEventDummy(ctx *BlobEventContext) (*BlobEventContext, error) { - return ctx, nil -} - -type chainedBlobEventMiddleware struct { - fun BlobEventMiddleware - nextFunc BlobEventHandler -} - -// automatically finalize chain with dummy function -func (c *chainedBlobEventMiddleware) invoke(ctx *BlobEventContext) (*BlobEventContext, error) { - if c.nextFunc == nil { - c.nextFunc = BlobEventDummy - } - - return c.fun(ctx, c.nextFunc) -} - -type blobEventMiddlewareChain struct { - chain []*chainedBlobEventMiddleware -} - -func (h *blobEventMiddlewareChain) invoke(ctx *BlobEventContext, next BlobEventHandler) (*BlobEventContext, error) { - // Complete the chain - h.chain[len(h.chain)-1].nextFunc = next - - return h.chain[0].invoke(ctx) -} - -// ComposeEventMiddleware - Composes an array of middleware into a single middleware -func ComposeBlobEventMiddleware(funcs ...BlobEventMiddleware) BlobEventMiddleware { - mwareChain := &blobEventMiddlewareChain{ - chain: make([]*chainedBlobEventMiddleware, len(funcs)), - } - - var nextFunc BlobEventHandler = nil - for i := len(funcs) - 1; i >= 0; i = i - 1 { - cm := &chainedBlobEventMiddleware{ - fun: funcs[i], - nextFunc: nextFunc, - } - nextFunc = cm.invoke - mwareChain.chain[i] = cm - } - - return mwareChain.invoke -} diff --git a/handler/context.go b/handler/context.go deleted file mode 100644 index ba56501..0000000 --- a/handler/context.go +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package handler - -import ( - http "github.com/nitrictech/nitric/core/pkg/proto/apis/v1" - schedules "github.com/nitrictech/nitric/core/pkg/proto/schedules/v1" - storage "github.com/nitrictech/nitric/core/pkg/proto/storage/v1" - topics "github.com/nitrictech/nitric/core/pkg/proto/topics/v1" - websockets "github.com/nitrictech/nitric/core/pkg/proto/websockets/v1" -) - -type HttpContext struct { - id string - Request HttpRequest - Response *HttpResponse - Extras map[string]interface{} -} - -func (c *HttpContext) ToClientMessage() *http.ClientMessage { - headers := make(map[string]*http.HeaderValue) - for k, v := range c.Response.Headers { - headers[k] = &http.HeaderValue{ - Value: v, - } - } - - return &http.ClientMessage{ - Id: c.id, - Content: &http.ClientMessage_HttpResponse{ - HttpResponse: &http.HttpResponse{ - Status: int32(c.Response.Status), - Headers: headers, - Body: c.Response.Body, - }, - }, - } -} - -func NewHttpContext(msg *http.ServerMessage) *HttpContext { - req := msg.GetHttpRequest() - - headers := make(map[string][]string) - for k, v := range req.Headers { - headers[k] = v.GetValue() - } - - query := make(map[string][]string) - for k, v := range req.QueryParams { - query[k] = v.GetValue() - } - - return &HttpContext{ - id: msg.Id, - Request: &httpRequestImpl{ - method: req.Method, - path: req.Path, - pathParams: req.PathParams, - query: query, - headers: headers, - data: req.Body, - }, - Response: &HttpResponse{ - Status: 200, - Headers: map[string][]string{}, - Body: nil, - }, - } -} - -func (c *HttpContext) WithError(err error) { - c.Response = &HttpResponse{ - Status: 500, - Headers: map[string][]string{ - "Content-Type": {"text/plain"}, - }, - Body: []byte("Internal Server Error"), - } -} - -type MessageContext struct { - id string - Request MessageRequest - Response *MessageResponse - Extras map[string]interface{} -} - -func (c *MessageContext) ToClientMessage() *topics.ClientMessage { - return &topics.ClientMessage{ - Id: c.id, - Content: &topics.ClientMessage_MessageResponse{ - MessageResponse: &topics.MessageResponse{ - Success: true, - }, - }, - } -} - -func NewMessageContext(msg *topics.ServerMessage) *MessageContext { - return &MessageContext{ - id: msg.Id, - Request: &messageRequestImpl{ - topicName: msg.GetMessageRequest().TopicName, - message: msg.GetMessageRequest().Message.GetStructPayload().AsMap(), - }, - Response: &MessageResponse{ - Success: true, - }, - } -} - -func (c *MessageContext) WithError(err error) { - c.Response = &MessageResponse{ - Success: false, - } -} - -type IntervalContext struct { - id string - Request IntervalRequest - Response *IntervalResponse - Extras map[string]interface{} -} - -func (c *IntervalContext) ToClientMessage() *schedules.ClientMessage { - return &schedules.ClientMessage{ - Id: c.id, - Content: &schedules.ClientMessage_IntervalResponse{ - IntervalResponse: &schedules.IntervalResponse{}, - }, - } -} - -func NewIntervalContext(msg *schedules.ServerMessage) *IntervalContext { - return &IntervalContext{ - id: msg.Id, - Request: &intervalRequestImpl{ - scheduleName: msg.GetIntervalRequest().ScheduleName, - }, - Response: &IntervalResponse{ - Success: true, - }, - } -} - -func (c *IntervalContext) WithError(err error) { - c.Response = &IntervalResponse{ - Success: false, - } -} - -type BlobEventContext struct { - id string - Request BlobEventRequest - Response *BlobEventResponse - Extras map[string]interface{} -} - -func (c *BlobEventContext) ToClientMessage() *storage.ClientMessage { - return &storage.ClientMessage{ - Id: c.id, - Content: &storage.ClientMessage_BlobEventResponse{ - BlobEventResponse: &storage.BlobEventResponse{ - Success: c.Response.Success, - }, - }, - } -} - -func NewBlobEventContext(msg *storage.ServerMessage) *BlobEventContext { - req := msg.GetBlobEventRequest() - - return &BlobEventContext{ - id: msg.Id, - Request: &blobEventRequestImpl{ - key: req.GetBlobEvent().Key, - }, - Response: &BlobEventResponse{ - Success: true, - }, - } -} - -func (c *BlobEventContext) WithError(err error) { - c.Response = &BlobEventResponse{ - Success: false, - } -} - -type FileEventContext struct { - Request FileEventRequest - Response *FileEventResponse - Extras map[string]interface{} -} - -type WebsocketContext struct { - id string - Request WebsocketRequest - Response *WebsocketResponse - Extras map[string]interface{} -} - -func (c *WebsocketContext) ToClientMessage() *websockets.ClientMessage { - return &websockets.ClientMessage{ - Id: c.id, - Content: &websockets.ClientMessage_WebsocketEventResponse{ - WebsocketEventResponse: &websockets.WebsocketEventResponse{ - WebsocketResponse: &websockets.WebsocketEventResponse_ConnectionResponse{ - ConnectionResponse: &websockets.WebsocketConnectionResponse{ - Reject: c.Response.Reject, - }, - }, - }, - }, - } -} - -func NewWebsocketContext(msg *websockets.ServerMessage) *WebsocketContext { - req := msg.GetWebsocketEventRequest() - - var eventType WebsocketEventType - switch req.WebsocketEvent.(type) { - case *websockets.WebsocketEventRequest_Disconnection: - eventType = WebsocketDisconnect - case *websockets.WebsocketEventRequest_Message: - eventType = WebsocketMessage - default: - eventType = WebsocketConnect - } - - queryParams := make(map[string]*http.QueryValue) - if eventType == WebsocketConnect { - for key, value := range req.GetConnection().GetQueryParams() { - queryParams[key] = &http.QueryValue{ - Value: value.Value, - } - } - } - - var _message string = "" - if req.GetMessage() != nil { - _message = string(req.GetMessage().Body) - } - - return &WebsocketContext{ - id: msg.Id, - Request: &websocketRequestImpl{ - socketName: req.SocketName, - eventType: eventType, - connectionId: req.ConnectionId, - queryParams: queryParams, - message: _message, - }, - Response: &WebsocketResponse{ - Reject: false, - }, - } -} - -func (c *WebsocketContext) WithError(err error) { - c.Response = &WebsocketResponse{ - Reject: true, - } -} diff --git a/handler/file_event.go b/handler/file_event.go deleted file mode 100644 index bfa5caf..0000000 --- a/handler/file_event.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package handler - -type ( - FileEventHandler = func(*FileEventContext) (*FileEventContext, error) - FileEventMiddleware = func(*FileEventContext, FileEventHandler) (*FileEventContext, error) -) - -func fileEventDummy(ctx *FileEventContext) (*FileEventContext, error) { - return ctx, nil -} - -type chainedFileEventMiddleware struct { - fun FileEventMiddleware - nextFunc FileEventHandler -} - -// automatically finalize chain with dummy function -func (c *chainedFileEventMiddleware) invoke(ctx *FileEventContext) (*FileEventContext, error) { - if c.nextFunc == nil { - c.nextFunc = fileEventDummy - } - - return c.fun(ctx, c.nextFunc) -} - -type fileEventMiddlewareChain struct { - chain []*chainedFileEventMiddleware -} - -func (h *fileEventMiddlewareChain) invoke(ctx *FileEventContext, next FileEventHandler) (*FileEventContext, error) { - // Complete the chain - h.chain[len(h.chain)-1].nextFunc = next - - return h.chain[0].invoke(ctx) -} - -// ComposeEventMiddleware - Composes an array of middleware into a single middleware -func ComposeFileEventMiddleware(funcs ...FileEventMiddleware) FileEventMiddleware { - mwareChain := &fileEventMiddlewareChain{ - chain: make([]*chainedFileEventMiddleware, len(funcs)), - } - - var nextFunc FileEventHandler = nil - for i := len(funcs) - 1; i >= 0; i = i - 1 { - cm := &chainedFileEventMiddleware{ - fun: funcs[i], - nextFunc: nextFunc, - } - nextFunc = cm.invoke - mwareChain.chain[i] = cm - } - - return mwareChain.invoke -} diff --git a/handler/http.go b/handler/http.go deleted file mode 100644 index bfef1d1..0000000 --- a/handler/http.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package handler - -import "fmt" - -type ( - HttpHandler = func(*HttpContext) (*HttpContext, error) - HttpMiddleware = func(*HttpContext, HttpHandler) (*HttpContext, error) -) - -func HttpDummy(ctx *HttpContext) (*HttpContext, error) { - return ctx, nil -} - -type chainedHttpMiddleware struct { - fun HttpMiddleware - nextFunc HttpHandler -} - -// automatically finalize chain with dummy function -func (c *chainedHttpMiddleware) invoke(ctx *HttpContext) (*HttpContext, error) { - // Chains are left open-ended so middleware can continue to be linked - // If the chain is incomplete, set a chained dummy handler for safety - if c.nextFunc == nil { - c.nextFunc = HttpDummy - } - - return c.fun(ctx, c.nextFunc) -} - -type httpMiddlewareChain struct { - chain []*chainedHttpMiddleware -} - -func (h *httpMiddlewareChain) invoke(ctx *HttpContext, next HttpHandler) (*HttpContext, error) { - if len(h.chain) == 0 { - return nil, fmt.Errorf("there are no middleware in this chain") - } - // Complete the chain - h.chain[len(h.chain)-1].nextFunc = next - - return h.chain[0].invoke(ctx) -} - -// ComposeHttpMiddleware - Composes an array of middleware into a single middleware -func ComposeHttpMiddleware(funcs ...HttpMiddleware) HttpMiddleware { - mwareChain := &httpMiddlewareChain{ - chain: make([]*chainedHttpMiddleware, len(funcs)), - } - - var nextFunc HttpHandler = nil - for i := len(funcs) - 1; i >= 0; i = i - 1 { - if funcs[i] == nil { - fmt.Println("this func is empty") - } - - cm := &chainedHttpMiddleware{ - fun: funcs[i], - nextFunc: nextFunc, - } - nextFunc = cm.invoke - mwareChain.chain[i] = cm - } - - return mwareChain.invoke -} diff --git a/handler/interval.go b/handler/interval.go deleted file mode 100644 index 4d37cd4..0000000 --- a/handler/interval.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package handler - -type ( - IntervalHandler = func(*IntervalContext) (*IntervalContext, error) - IntervalMiddleware = func(*IntervalContext, IntervalHandler) (*IntervalContext, error) -) - -func IntervalDummy(ctx *IntervalContext) (*IntervalContext, error) { - return ctx, nil -} - -type chainedIntervalMiddleware struct { - fun IntervalMiddleware - nextFunc IntervalHandler -} - -// automatically finalize chain with dummy function -func (c *chainedIntervalMiddleware) invoke(ctx *IntervalContext) (*IntervalContext, error) { - if c.nextFunc == nil { - c.nextFunc = IntervalDummy - } - - return c.fun(ctx, c.nextFunc) -} - -type intervalMiddlewareChain struct { - chain []*chainedIntervalMiddleware -} - -func (h *intervalMiddlewareChain) invoke(ctx *IntervalContext, next IntervalHandler) (*IntervalContext, error) { - // Complete the chain - h.chain[len(h.chain)-1].nextFunc = next - - return h.chain[0].invoke(ctx) -} - -// ComposeIntervalMiddleware - Composes an array of middleware into a single middleware -func ComposeIntervalMiddleware(funcs ...IntervalMiddleware) IntervalMiddleware { - mwareChain := &intervalMiddlewareChain{ - chain: make([]*chainedIntervalMiddleware, len(funcs)), - } - - var nextFunc IntervalHandler = nil - for i := len(funcs) - 1; i >= 0; i = i - 1 { - cm := &chainedIntervalMiddleware{ - fun: funcs[i], - nextFunc: nextFunc, - } - nextFunc = cm.invoke - mwareChain.chain[i] = cm - } - - return mwareChain.invoke -} diff --git a/handler/message.go b/handler/message.go deleted file mode 100644 index 6eac5ee..0000000 --- a/handler/message.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package handler - -type ( - MessageHandler = func(*MessageContext) (*MessageContext, error) - MessageMiddleware = func(*MessageContext, MessageHandler) (*MessageContext, error) -) - -func MessageDummy(ctx *MessageContext) (*MessageContext, error) { - return ctx, nil -} - -type chainedMessageMiddleware struct { - fun MessageMiddleware - nextFunc MessageHandler -} - -// automatically finalize chain with dummy function -func (c *chainedMessageMiddleware) invoke(ctx *MessageContext) (*MessageContext, error) { - if c.nextFunc == nil { - c.nextFunc = MessageDummy - } - - return c.fun(ctx, c.nextFunc) -} - -type messageMiddlewareChain struct { - chain []*chainedMessageMiddleware -} - -func (h *messageMiddlewareChain) invoke(ctx *MessageContext, next MessageHandler) (*MessageContext, error) { - // Complete the chain - h.chain[len(h.chain)-1].nextFunc = next - - return h.chain[0].invoke(ctx) -} - -// ComposeMessageMiddleware - Composes an array of middleware into a single middleware -func ComposeMessageMiddleware(funcs ...MessageMiddleware) MessageMiddleware { - mwareChain := &messageMiddlewareChain{ - chain: make([]*chainedMessageMiddleware, len(funcs)), - } - - var nextFunc MessageHandler = nil - for i := len(funcs) - 1; i >= 0; i = i - 1 { - cm := &chainedMessageMiddleware{ - fun: funcs[i], - nextFunc: nextFunc, - } - nextFunc = cm.invoke - mwareChain.chain[i] = cm - } - - return mwareChain.invoke -} diff --git a/handler/request.go b/handler/request.go deleted file mode 100644 index 1d523cc..0000000 --- a/handler/request.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package handler - -import ( - "github.com/nitrictech/go-sdk/api/storage" - v1 "github.com/nitrictech/nitric/core/pkg/proto/apis/v1" -) - -// Http - -type HttpRequest interface { - Method() string - Path() string - Data() []byte - Query() map[string][]string - Headers() map[string][]string - PathParams() map[string]string -} - -type httpRequestImpl struct { - method string - path string - data []byte - query map[string][]string - headers map[string][]string - pathParams map[string]string -} - -func (h *httpRequestImpl) Method() string { - return h.method -} - -func (h *httpRequestImpl) Path() string { - return h.path -} - -func (h *httpRequestImpl) Data() []byte { - return h.data -} - -func (h *httpRequestImpl) Query() map[string][]string { - return h.query -} - -func (h *httpRequestImpl) Headers() map[string][]string { - return h.headers -} - -func (h *httpRequestImpl) PathParams() map[string]string { - return h.pathParams -} - -// Message - -type MessageRequest interface { - TopicName() string - Message() map[string]interface{} -} - -type messageRequestImpl struct { - topicName string - message map[string]interface{} -} - -func (m *messageRequestImpl) TopicName() string { - return m.topicName -} - -func (m *messageRequestImpl) Message() map[string]interface{} { - return m.message -} - -// Interval - -type IntervalRequest interface { - ScheduleName() string -} - -type intervalRequestImpl struct { - scheduleName string -} - -func (i *intervalRequestImpl) ScheduleName() string { - return i.scheduleName -} - -// Blob Event - -type BlobEventType string - -var BlobEventTypes = []BlobEventType{WriteNotification, DeleteNotification} - -const ( - WriteNotification BlobEventType = "write" - DeleteNotification BlobEventType = "delete" -) - -type BlobEventRequest interface { - Key() string - NotificationType() BlobEventType -} - -type blobEventRequestImpl struct { - key string - notificationType BlobEventType -} - -func (b *blobEventRequestImpl) Key() string { - return b.key -} - -func (b *blobEventRequestImpl) NotificationType() BlobEventType { - return b.notificationType -} - -// File Event - -type FileEventRequest interface { - Bucket() *storage.Bucket - NotificationType() BlobEventType -} - -type fileEventRequestImpl struct { - bucket storage.Bucket - notificationType BlobEventType -} - -func (f *fileEventRequestImpl) Bucket() storage.Bucket { - return f.bucket -} - -func (f *fileEventRequestImpl) NotificationType() BlobEventType { - return f.notificationType -} - -// Websocket - -type WebsocketEventType string - -var WebsocketEventTypes = []WebsocketEventType{WebsocketConnect, WebsocketDisconnect, WebsocketMessage} - -const ( - WebsocketConnect WebsocketEventType = "connect" - WebsocketDisconnect WebsocketEventType = "disconnect" - WebsocketMessage WebsocketEventType = "message" -) - -type WebsocketRequest interface { - SocketName() string - EventType() WebsocketEventType - ConnectionID() string - QueryParams() map[string][]string - Message() string -} - -type websocketRequestImpl struct { - socketName string - eventType WebsocketEventType - connectionId string - queryParams map[string]*v1.QueryValue - message string -} - -func (w *websocketRequestImpl) SocketName() string { - return w.socketName -} - -func (w *websocketRequestImpl) EventType() WebsocketEventType { - return w.eventType -} - -func (w *websocketRequestImpl) ConnectionID() string { - return w.connectionId -} - -func (w *websocketRequestImpl) QueryParams() map[string][]string { - queryParams := map[string][]string{} - - for k, v := range w.queryParams { - queryParams[k] = v.Value - } - - return queryParams -} - -func (w *websocketRequestImpl) Message() string { - return w.message -} diff --git a/handler/websocket.go b/handler/websocket.go deleted file mode 100644 index 41b548e..0000000 --- a/handler/websocket.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package handler - -type ( - WebsocketHandler = func(*WebsocketContext) (*WebsocketContext, error) - WebsocketMiddleware = func(*WebsocketContext, WebsocketHandler) (*WebsocketContext, error) -) - -func WebsocketDummy(ctx *WebsocketContext) (*WebsocketContext, error) { - return ctx, nil -} - -type chainedWebsocketMiddleware struct { - fun WebsocketMiddleware - nextFunc WebsocketHandler -} - -// automatically finalize chain with dummy function -func (c *chainedWebsocketMiddleware) invoke(ctx *WebsocketContext) (*WebsocketContext, error) { - if c.nextFunc == nil { - c.nextFunc = WebsocketDummy - } - - return c.fun(ctx, c.nextFunc) -} - -type websocketMiddlewareChain struct { - chain []*chainedWebsocketMiddleware -} - -func (h *websocketMiddlewareChain) invoke(ctx *WebsocketContext, next WebsocketHandler) (*WebsocketContext, error) { - // Complete the chain - h.chain[len(h.chain)-1].nextFunc = next - - return h.chain[0].invoke(ctx) -} - -// ComposeWebsocketMiddleware - Composes an array of middleware into a single middleware -func ComposeWebsocketMiddleware(funcs ...WebsocketMiddleware) WebsocketMiddleware { - mwareChain := &websocketMiddlewareChain{ - chain: make([]*chainedWebsocketMiddleware, len(funcs)), - } - - var nextFunc WebsocketHandler = nil - for i := len(funcs) - 1; i >= 0; i = i - 1 { - cm := &chainedWebsocketMiddleware{ - fun: funcs[i], - nextFunc: nextFunc, - } - nextFunc = cm.invoke - mwareChain.chain[i] = cm - } - - return mwareChain.invoke -} diff --git a/api/secrets/secret_value.go b/internal/grpc/grpcx.go similarity index 51% rename from api/secrets/secret_value.go rename to internal/grpc/grpcx.go index e941f61..97b7976 100644 --- a/api/secrets/secret_value.go +++ b/internal/grpc/grpcx.go @@ -12,31 +12,37 @@ // See the License for the specific language governing permissions and // limitations under the License. -package secrets - -// SecretValue - Interface -type SecretValue interface { - // Version - Returns a reference to the version of this value - Version() SecretVersionRef - // AsBytes - Returns the secret value as bytes - AsBytes() []byte - // AsString - Returns the secret value as a string - AsString() string -} +package grpcx -type secretValueImpl struct { - version SecretVersionRef - val []byte -} +import ( + "sync" + + "google.golang.org/grpc" -func (s *secretValueImpl) Version() SecretVersionRef { - return s.version + "github.com/nitrictech/go-sdk/constants" +) + +type grpcManager struct { + conn grpc.ClientConnInterface + connMutex sync.Mutex } -func (s *secretValueImpl) AsBytes() []byte { - return s.val +var m = grpcManager{ + conn: nil, + connMutex: sync.Mutex{}, } -func (s *secretValueImpl) AsString() string { - return string(s.AsBytes()) +func GetConnection() (grpc.ClientConnInterface, error) { + m.connMutex.Lock() + defer m.connMutex.Unlock() + + if m.conn == nil { + conn, err := grpc.NewClient(constants.NitricAddress(), constants.DefaultOptions()...) + if err != nil { + return nil, err + } + m.conn = conn + } + + return m.conn, nil } diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go new file mode 100644 index 0000000..014a25b --- /dev/null +++ b/internal/handlers/handlers.go @@ -0,0 +1,58 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package handlers + +import "fmt" + +type ( + Handler[T any] func(context *T) error + Middleware[T any] func(Handler[T]) Handler[T] +) + +// fromInterface - Converts a function to a Handler +// Valid function types are: +// func() +// func() error +// func(*T) +// func(*T) error +// Handler[T] +// If the function is not a valid type, an error is returned +func HandlerFromInterface[T any](handler interface{}) (Handler[T], error) { + var typedHandler Handler[T] + switch handlerType := handler.(type) { + case func(): + typedHandler = func(ctx *T) error { + handlerType() + return nil + } + case func() error: + typedHandler = func(ctx *T) error { + return handlerType() + } + case func(*T): + typedHandler = func(ctx *T) error { + handlerType(ctx) + return nil + } + case func(*T) error: + typedHandler = Handler[T](handlerType) + case Handler[T]: + typedHandler = handlerType + default: + return nil, fmt.Errorf("invalid handler type: %T", handler) + } + + return typedHandler, nil +} diff --git a/internal/handlers/handlers_test.go b/internal/handlers/handlers_test.go new file mode 100644 index 0000000..e9cd53f --- /dev/null +++ b/internal/handlers/handlers_test.go @@ -0,0 +1,75 @@ +// Copyright 2021 Nitric Technologies Pty Ltd. +// +// 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. + +package handlers + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("handler", func() { + // func() + // func() error + // func(*T) + // func(*T) error + // func(*T, Handler[T]) error + // Handler[T] + Context("HandlerFromInterface", func() { + When("interface{} is func()", func() { + It("should return a valid handler", func() { + handler, err := HandlerFromInterface[any](func() {}) + + Expect(err).To(BeNil()) + Expect(handler).ToNot(BeNil()) + }) + }) + + When("interface{} is func() error", func() { + It("should return a valid handler", func() { + handler, err := HandlerFromInterface[any](func() error { return nil }) + + Expect(err).To(BeNil()) + Expect(handler).ToNot(BeNil()) + }) + }) + + When("interface{} is func(*T)", func() { + It("should return a valid handler", func() { + handler, err := HandlerFromInterface[string](func(*string) {}) + + Expect(err).To(BeNil()) + Expect(handler).ToNot(BeNil()) + }) + }) + + When("interface{} is func(*T) error", func() { + It("should return a valid handler", func() { + handler, err := HandlerFromInterface[string](func(*string) error { return nil }) + + Expect(err).To(BeNil()) + Expect(handler).ToNot(BeNil()) + }) + }) + + When("interface{} is not a valid type", func() { + It("should return an error", func() { + handler, err := HandlerFromInterface[string](func() (error, error) { return nil, nil }) + + Expect(err).ToNot(BeNil()) + Expect(handler).To(BeNil()) + }) + }) + }) +}) diff --git a/licenses.go b/licenses.go index 1265924..7656872 100644 --- a/licenses.go +++ b/licenses.go @@ -18,13 +18,16 @@ package main // This main package is a workaround for binary license scanning that forces transitive dependencies in // Code we're distributing to be analyzed import ( - _ "github.com/nitrictech/go-sdk/api/keyvalue" - _ "github.com/nitrictech/go-sdk/api/queues" - _ "github.com/nitrictech/go-sdk/api/secrets" - _ "github.com/nitrictech/go-sdk/api/storage" - _ "github.com/nitrictech/go-sdk/api/topics" _ "github.com/nitrictech/go-sdk/nitric" - _ "github.com/nitrictech/go-sdk/workers" + _ "github.com/nitrictech/go-sdk/nitric/apis" + _ "github.com/nitrictech/go-sdk/nitric/errors" + _ "github.com/nitrictech/go-sdk/nitric/keyvalue" + _ "github.com/nitrictech/go-sdk/nitric/queues" + _ "github.com/nitrictech/go-sdk/nitric/schedules" + _ "github.com/nitrictech/go-sdk/nitric/secrets" + _ "github.com/nitrictech/go-sdk/nitric/storage" + _ "github.com/nitrictech/go-sdk/nitric/topics" + _ "github.com/nitrictech/go-sdk/nitric/websockets" ) func main() {} diff --git a/mocks/mockapi/keyvalue.go b/mocks/mockapi/keyvalue.go deleted file mode 100644 index b393f22..0000000 --- a/mocks/mockapi/keyvalue.go +++ /dev/null @@ -1,151 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/nitrictech/go-sdk/api/keyvalue (interfaces: KeyValue,Store) - -// Package mockapi is a generated GoMock package. -package mockapi - -import ( - context "context" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - keyvalue "github.com/nitrictech/go-sdk/api/keyvalue" - kvstorepb "github.com/nitrictech/nitric/core/pkg/proto/kvstore/v1" -) - -// MockKeyValue is a mock of KeyValue interface. -type MockKeyValue struct { - ctrl *gomock.Controller - recorder *MockKeyValueMockRecorder -} - -// MockKeyValueMockRecorder is the mock recorder for MockKeyValue. -type MockKeyValueMockRecorder struct { - mock *MockKeyValue -} - -// NewMockKeyValue creates a new mock instance. -func NewMockKeyValue(ctrl *gomock.Controller) *MockKeyValue { - mock := &MockKeyValue{ctrl: ctrl} - mock.recorder = &MockKeyValueMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockKeyValue) EXPECT() *MockKeyValueMockRecorder { - return m.recorder -} - -// Store mocks base method. -func (m *MockKeyValue) Store(arg0 string) keyvalue.Store { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Store", arg0) - ret0, _ := ret[0].(keyvalue.Store) - return ret0 -} - -// Store indicates an expected call of Store. -func (mr *MockKeyValueMockRecorder) Store(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Store", reflect.TypeOf((*MockKeyValue)(nil).Store), arg0) -} - -// MockStore is a mock of Store interface. -type MockStore struct { - ctrl *gomock.Controller - recorder *MockStoreMockRecorder -} - -// MockStoreMockRecorder is the mock recorder for MockStore. -type MockStoreMockRecorder struct { - mock *MockStore -} - -// NewMockStore creates a new mock instance. -func NewMockStore(ctrl *gomock.Controller) *MockStore { - mock := &MockStore{ctrl: ctrl} - mock.recorder = &MockStoreMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockStore) EXPECT() *MockStoreMockRecorder { - return m.recorder -} - -// Delete mocks base method. -func (m *MockStore) Delete(arg0 context.Context, arg1 string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// Delete indicates an expected call of Delete. -func (mr *MockStoreMockRecorder) Delete(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockStore)(nil).Delete), arg0, arg1) -} - -// Get mocks base method. -func (m *MockStore) Get(arg0 context.Context, arg1 string) (map[string]interface{}, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get", arg0, arg1) - ret0, _ := ret[0].(map[string]interface{}) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Get indicates an expected call of Get. -func (mr *MockStoreMockRecorder) Get(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockStore)(nil).Get), arg0, arg1) -} - -// Keys mocks base method. -func (m *MockStore) Keys(arg0 context.Context, arg1 ...func(*kvstorepb.KvStoreScanKeysRequest)) (*keyvalue.KeyStream, error) { - m.ctrl.T.Helper() - varargs := []interface{}{arg0} - for _, a := range arg1 { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "Keys", varargs...) - ret0, _ := ret[0].(*keyvalue.KeyStream) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Keys indicates an expected call of Keys. -func (mr *MockStoreMockRecorder) Keys(arg0 interface{}, arg1 ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0}, arg1...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Keys", reflect.TypeOf((*MockStore)(nil).Keys), varargs...) -} - -// Name mocks base method. -func (m *MockStore) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name. -func (mr *MockStoreMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockStore)(nil).Name)) -} - -// Set mocks base method. -func (m *MockStore) Set(arg0 context.Context, arg1 string, arg2 map[string]interface{}) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Set", arg0, arg1, arg2) - ret0, _ := ret[0].(error) - return ret0 -} - -// Set indicates an expected call of Set. -func (mr *MockStoreMockRecorder) Set(arg0, arg1, arg2 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockStore)(nil).Set), arg0, arg1, arg2) -} diff --git a/mocks/mockapi/queues.go b/mocks/mockapi/queues.go deleted file mode 100644 index 0d97d55..0000000 --- a/mocks/mockapi/queues.go +++ /dev/null @@ -1,117 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/nitrictech/go-sdk/api/queues (interfaces: Queues,Queue) - -// Package mockapi is a generated GoMock package. -package mockapi - -import ( - context "context" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - queues "github.com/nitrictech/go-sdk/api/queues" -) - -// MockQueues is a mock of Queues interface. -type MockQueues struct { - ctrl *gomock.Controller - recorder *MockQueuesMockRecorder -} - -// MockQueuesMockRecorder is the mock recorder for MockQueues. -type MockQueuesMockRecorder struct { - mock *MockQueues -} - -// NewMockQueues creates a new mock instance. -func NewMockQueues(ctrl *gomock.Controller) *MockQueues { - mock := &MockQueues{ctrl: ctrl} - mock.recorder = &MockQueuesMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockQueues) EXPECT() *MockQueuesMockRecorder { - return m.recorder -} - -// Queue mocks base method. -func (m *MockQueues) Queue(arg0 string) queues.Queue { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Queue", arg0) - ret0, _ := ret[0].(queues.Queue) - return ret0 -} - -// Queue indicates an expected call of Queue. -func (mr *MockQueuesMockRecorder) Queue(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Queue", reflect.TypeOf((*MockQueues)(nil).Queue), arg0) -} - -// MockQueue is a mock of Queue interface. -type MockQueue struct { - ctrl *gomock.Controller - recorder *MockQueueMockRecorder -} - -// MockQueueMockRecorder is the mock recorder for MockQueue. -type MockQueueMockRecorder struct { - mock *MockQueue -} - -// NewMockQueue creates a new mock instance. -func NewMockQueue(ctrl *gomock.Controller) *MockQueue { - mock := &MockQueue{ctrl: ctrl} - mock.recorder = &MockQueueMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockQueue) EXPECT() *MockQueueMockRecorder { - return m.recorder -} - -// Dequeue mocks base method. -func (m *MockQueue) Dequeue(arg0 context.Context, arg1 int) ([]queues.ReceivedMessage, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Dequeue", arg0, arg1) - ret0, _ := ret[0].([]queues.ReceivedMessage) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Dequeue indicates an expected call of Dequeue. -func (mr *MockQueueMockRecorder) Dequeue(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Dequeue", reflect.TypeOf((*MockQueue)(nil).Dequeue), arg0, arg1) -} - -// Enqueue mocks base method. -func (m *MockQueue) Enqueue(arg0 context.Context, arg1 []map[string]interface{}) ([]*queues.FailedMessage, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Enqueue", arg0, arg1) - ret0, _ := ret[0].([]*queues.FailedMessage) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Enqueue indicates an expected call of Enqueue. -func (mr *MockQueueMockRecorder) Enqueue(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Enqueue", reflect.TypeOf((*MockQueue)(nil).Enqueue), arg0, arg1) -} - -// Name mocks base method. -func (m *MockQueue) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name. -func (mr *MockQueueMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockQueue)(nil).Name)) -} diff --git a/mocks/mockapi/secrets.go b/mocks/mockapi/secrets.go deleted file mode 100644 index 381550c..0000000 --- a/mocks/mockapi/secrets.go +++ /dev/null @@ -1,130 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/nitrictech/go-sdk/api/secrets (interfaces: Secrets,SecretRef) - -// Package mockapi is a generated GoMock package. -package mockapi - -import ( - context "context" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - secrets "github.com/nitrictech/go-sdk/api/secrets" -) - -// MockSecrets is a mock of Secrets interface. -type MockSecrets struct { - ctrl *gomock.Controller - recorder *MockSecretsMockRecorder -} - -// MockSecretsMockRecorder is the mock recorder for MockSecrets. -type MockSecretsMockRecorder struct { - mock *MockSecrets -} - -// NewMockSecrets creates a new mock instance. -func NewMockSecrets(ctrl *gomock.Controller) *MockSecrets { - mock := &MockSecrets{ctrl: ctrl} - mock.recorder = &MockSecretsMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockSecrets) EXPECT() *MockSecretsMockRecorder { - return m.recorder -} - -// Secret mocks base method. -func (m *MockSecrets) Secret(arg0 string) secrets.SecretRef { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Secret", arg0) - ret0, _ := ret[0].(secrets.SecretRef) - return ret0 -} - -// Secret indicates an expected call of Secret. -func (mr *MockSecretsMockRecorder) Secret(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Secret", reflect.TypeOf((*MockSecrets)(nil).Secret), arg0) -} - -// MockSecretRef is a mock of SecretRef interface. -type MockSecretRef struct { - ctrl *gomock.Controller - recorder *MockSecretRefMockRecorder -} - -// MockSecretRefMockRecorder is the mock recorder for MockSecretRef. -type MockSecretRefMockRecorder struct { - mock *MockSecretRef -} - -// NewMockSecretRef creates a new mock instance. -func NewMockSecretRef(ctrl *gomock.Controller) *MockSecretRef { - mock := &MockSecretRef{ctrl: ctrl} - mock.recorder = &MockSecretRefMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockSecretRef) EXPECT() *MockSecretRefMockRecorder { - return m.recorder -} - -// Latest mocks base method. -func (m *MockSecretRef) Latest() secrets.SecretVersionRef { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Latest") - ret0, _ := ret[0].(secrets.SecretVersionRef) - return ret0 -} - -// Latest indicates an expected call of Latest. -func (mr *MockSecretRefMockRecorder) Latest() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Latest", reflect.TypeOf((*MockSecretRef)(nil).Latest)) -} - -// Name mocks base method. -func (m *MockSecretRef) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name. -func (mr *MockSecretRefMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockSecretRef)(nil).Name)) -} - -// Put mocks base method. -func (m *MockSecretRef) Put(arg0 context.Context, arg1 []byte) (secrets.SecretVersionRef, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Put", arg0, arg1) - ret0, _ := ret[0].(secrets.SecretVersionRef) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Put indicates an expected call of Put. -func (mr *MockSecretRefMockRecorder) Put(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockSecretRef)(nil).Put), arg0, arg1) -} - -// Version mocks base method. -func (m *MockSecretRef) Version(arg0 string) secrets.SecretVersionRef { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Version", arg0) - ret0, _ := ret[0].(secrets.SecretVersionRef) - return ret0 -} - -// Version indicates an expected call of Version. -func (mr *MockSecretRefMockRecorder) Version(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Version", reflect.TypeOf((*MockSecretRef)(nil).Version), arg0) -} diff --git a/mocks/mockapi/storage.go b/mocks/mockapi/storage.go deleted file mode 100644 index 0b77856..0000000 --- a/mocks/mockapi/storage.go +++ /dev/null @@ -1,116 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/nitrictech/go-sdk/api/storage (interfaces: Storage,Bucket) - -// Package mockapi is a generated GoMock package. -package mockapi - -import ( - context "context" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - storage "github.com/nitrictech/go-sdk/api/storage" -) - -// MockStorage is a mock of Storage interface. -type MockStorage struct { - ctrl *gomock.Controller - recorder *MockStorageMockRecorder -} - -// MockStorageMockRecorder is the mock recorder for MockStorage. -type MockStorageMockRecorder struct { - mock *MockStorage -} - -// NewMockStorage creates a new mock instance. -func NewMockStorage(ctrl *gomock.Controller) *MockStorage { - mock := &MockStorage{ctrl: ctrl} - mock.recorder = &MockStorageMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockStorage) EXPECT() *MockStorageMockRecorder { - return m.recorder -} - -// Bucket mocks base method. -func (m *MockStorage) Bucket(arg0 string) storage.Bucket { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Bucket", arg0) - ret0, _ := ret[0].(storage.Bucket) - return ret0 -} - -// Bucket indicates an expected call of Bucket. -func (mr *MockStorageMockRecorder) Bucket(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Bucket", reflect.TypeOf((*MockStorage)(nil).Bucket), arg0) -} - -// MockBucket is a mock of Bucket interface. -type MockBucket struct { - ctrl *gomock.Controller - recorder *MockBucketMockRecorder -} - -// MockBucketMockRecorder is the mock recorder for MockBucket. -type MockBucketMockRecorder struct { - mock *MockBucket -} - -// NewMockBucket creates a new mock instance. -func NewMockBucket(ctrl *gomock.Controller) *MockBucket { - mock := &MockBucket{ctrl: ctrl} - mock.recorder = &MockBucketMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockBucket) EXPECT() *MockBucketMockRecorder { - return m.recorder -} - -// File mocks base method. -func (m *MockBucket) File(arg0 string) storage.File { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "File", arg0) - ret0, _ := ret[0].(storage.File) - return ret0 -} - -// File indicates an expected call of File. -func (mr *MockBucketMockRecorder) File(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "File", reflect.TypeOf((*MockBucket)(nil).File), arg0) -} - -// Files mocks base method. -func (m *MockBucket) Files(arg0 context.Context) ([]storage.File, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Files", arg0) - ret0, _ := ret[0].([]storage.File) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Files indicates an expected call of Files. -func (mr *MockBucketMockRecorder) Files(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Files", reflect.TypeOf((*MockBucket)(nil).Files), arg0) -} - -// Name mocks base method. -func (m *MockBucket) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name. -func (mr *MockBucketMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockBucket)(nil).Name)) -} diff --git a/mocks/mockapi/topics.go b/mocks/mockapi/topics.go deleted file mode 100644 index ee0a470..0000000 --- a/mocks/mockapi/topics.go +++ /dev/null @@ -1,107 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/nitrictech/go-sdk/api/topics (interfaces: Topics,Topic) - -// Package mockapi is a generated GoMock package. -package mockapi - -import ( - context "context" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - topics "github.com/nitrictech/go-sdk/api/topics" - topicspb "github.com/nitrictech/nitric/core/pkg/proto/topics/v1" -) - -// MockTopics is a mock of Topics interface. -type MockTopics struct { - ctrl *gomock.Controller - recorder *MockTopicsMockRecorder -} - -// MockTopicsMockRecorder is the mock recorder for MockTopics. -type MockTopicsMockRecorder struct { - mock *MockTopics -} - -// NewMockTopics creates a new mock instance. -func NewMockTopics(ctrl *gomock.Controller) *MockTopics { - mock := &MockTopics{ctrl: ctrl} - mock.recorder = &MockTopicsMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockTopics) EXPECT() *MockTopicsMockRecorder { - return m.recorder -} - -// Topic mocks base method. -func (m *MockTopics) Topic(arg0 string) topics.Topic { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Topic", arg0) - ret0, _ := ret[0].(topics.Topic) - return ret0 -} - -// Topic indicates an expected call of Topic. -func (mr *MockTopicsMockRecorder) Topic(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Topic", reflect.TypeOf((*MockTopics)(nil).Topic), arg0) -} - -// MockTopic is a mock of Topic interface. -type MockTopic struct { - ctrl *gomock.Controller - recorder *MockTopicMockRecorder -} - -// MockTopicMockRecorder is the mock recorder for MockTopic. -type MockTopicMockRecorder struct { - mock *MockTopic -} - -// NewMockTopic creates a new mock instance. -func NewMockTopic(ctrl *gomock.Controller) *MockTopic { - mock := &MockTopic{ctrl: ctrl} - mock.recorder = &MockTopicMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockTopic) EXPECT() *MockTopicMockRecorder { - return m.recorder -} - -// Name mocks base method. -func (m *MockTopic) Name() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Name") - ret0, _ := ret[0].(string) - return ret0 -} - -// Name indicates an expected call of Name. -func (mr *MockTopicMockRecorder) Name() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockTopic)(nil).Name)) -} - -// Publish mocks base method. -func (m *MockTopic) Publish(arg0 context.Context, arg1 map[string]interface{}, arg2 ...func(*topicspb.TopicPublishRequest)) error { - m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - for _, a := range arg2 { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "Publish", varargs...) - ret0, _ := ret[0].(error) - return ret0 -} - -// Publish indicates an expected call of Publish. -func (mr *MockTopicMockRecorder) Publish(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Publish", reflect.TypeOf((*MockTopic)(nil).Publish), varargs...) -} diff --git a/nitric/api.go b/nitric/api.go deleted file mode 100644 index 5c2b84f..0000000 --- a/nitric/api.go +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package nitric - -import ( - "net/http" - "path" - "strings" - - "github.com/nitrictech/go-sdk/handler" - "github.com/nitrictech/go-sdk/workers" - apispb "github.com/nitrictech/nitric/core/pkg/proto/apis/v1" - resourcev1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" -) - -// Route providers convenience functions to register a handler in a single method. -type Route interface { - All(handler handler.HttpMiddleware, opts ...MethodOption) - Get(handler handler.HttpMiddleware, opts ...MethodOption) - Patch(handler handler.HttpMiddleware, opts ...MethodOption) - Put(handler handler.HttpMiddleware, opts ...MethodOption) - Post(handler handler.HttpMiddleware, opts ...MethodOption) - Delete(handler handler.HttpMiddleware, opts ...MethodOption) - Options(handler handler.HttpMiddleware, opts ...MethodOption) - ApiName() string -} - -type route struct { - path string - api *api - middleware handler.HttpMiddleware - manager Manager -} - -func composeRouteMiddleware(apiMiddleware handler.HttpMiddleware, routeMiddleware []handler.HttpMiddleware) handler.HttpMiddleware { - if apiMiddleware != nil && len(routeMiddleware) > 0 { - return handler.ComposeHttpMiddleware(apiMiddleware, handler.ComposeHttpMiddleware(routeMiddleware...)) - } - - if len(routeMiddleware) > 0 { - return handler.ComposeHttpMiddleware(routeMiddleware...) - } - - return apiMiddleware -} - -func (a *api) NewRoute(match string, middleware ...handler.HttpMiddleware) Route { - r, ok := a.routes[match] - if !ok { - r = &route{ - manager: a.manager, - path: path.Join(a.path, match), - api: a, - middleware: composeRouteMiddleware(a.middleware, middleware), - } - } - - return r -} - -func (r *route) ApiName() string { - return r.api.name -} - -func (r *route) AddMethodHandler(methods []string, middleware handler.HttpMiddleware, opts ...MethodOption) error { - bName := path.Join(r.api.name, r.path, strings.Join(methods, "-")) - - // default methodOptions will contain OidcOptions passed to API instance and securityDisabled to false - mo := &methodOptions{ - securityDisabled: false, - security: r.api.security, - } - - for _, o := range opts { - o(mo) - } - - composedHandler := middleware - if r.middleware != nil { - composedHandler = handler.ComposeHttpMiddleware(r.middleware, middleware) - } - - apiOpts := &apispb.ApiWorkerOptions{ - SecurityDisabled: mo.securityDisabled, - Security: map[string]*apispb.ApiWorkerScopes{}, - } - - if mo.security != nil && !mo.securityDisabled { - for _, oidcOption := range mo.security { - err := attachOidc(r.api.name, oidcOption) - if err != nil { - return err - } - - apiOpts.Security[oidcOption.Name] = &apispb.ApiWorkerScopes{ - Scopes: oidcOption.Scopes, - } - } - } - - registrationRequest := &apispb.RegistrationRequest{ - Path: r.path, - Api: r.api.name, - Methods: methods, - Options: apiOpts, - } - - wkr := workers.NewApiWorker(&workers.ApiWorkerOpts{ - RegistrationRequest: registrationRequest, - Middleware: composedHandler, - }) - - r.manager.addWorker("route:"+bName, wkr) - - return nil -} - -func (r *route) All(handler handler.HttpMiddleware, opts ...MethodOption) { - r.AddMethodHandler([]string{http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete, http.MethodOptions}, handler, opts...) -} - -func (r *route) Get(handler handler.HttpMiddleware, opts ...MethodOption) { - r.AddMethodHandler([]string{http.MethodGet}, handler, opts...) -} - -func (r *route) Post(handler handler.HttpMiddleware, opts ...MethodOption) { - r.AddMethodHandler([]string{http.MethodPost}, handler, opts...) -} - -func (r *route) Put(handler handler.HttpMiddleware, opts ...MethodOption) { - r.AddMethodHandler([]string{http.MethodPut}, handler, opts...) -} - -func (r *route) Patch(handler handler.HttpMiddleware, opts ...MethodOption) { - r.AddMethodHandler([]string{http.MethodPatch}, handler, opts...) -} - -func (r *route) Delete(handler handler.HttpMiddleware, opts ...MethodOption) { - r.AddMethodHandler([]string{http.MethodDelete}, handler, opts...) -} - -func (r *route) Options(handler handler.HttpMiddleware, opts ...MethodOption) { - r.AddMethodHandler([]string{http.MethodOptions}, handler, opts...) -} - -// Api Resource represents an HTTP API, capable of routing and securing incoming HTTP requests to handlers. -// path is the route path matcher e.g. '/home'. Supports path params via colon prefix e.g. '/customers/:customerId' -// handler the handler to register for callbacks. -// -// Note: to chain middleware use handler.ComposeHttpMiddlware() -type Api interface { - Get(path string, handler handler.HttpMiddleware, opts ...MethodOption) - Put(path string, handler handler.HttpMiddleware, opts ...MethodOption) - Patch(path string, handler handler.HttpMiddleware, opts ...MethodOption) - Post(path string, handler handler.HttpMiddleware, opts ...MethodOption) - Delete(path string, handler handler.HttpMiddleware, opts ...MethodOption) - Options(path string, handler handler.HttpMiddleware, opts ...MethodOption) - NewRoute(path string, middleware ...handler.HttpMiddleware) Route -} - -type ApiDetails struct { - Details - URL string -} - -type api struct { - name string - routes map[string]Route - manager Manager - securityRules map[string]interface{} - security []OidcOptions - path string - middleware handler.HttpMiddleware -} - -// NewApi Registers a new API Resource. -// -// The returned API object can be used to register Routes and Methods, with Handlers. -func NewApi(name string, opts ...ApiOption) (Api, error) { - a := &api{ - name: name, - routes: map[string]Route{}, - manager: defaultManager, - } - - // Apply options - for _, o := range opts { - o(a) - } - - apiResource := &resourcev1.ApiResource{} - - // Attaching OIDC Options to API - if a.security != nil { - for _, oidcOption := range a.security { - attachOidc(a.name, oidcOption) - - if apiResource.GetSecurity() == nil { - apiResource.Security = make(map[string]*resourcev1.ApiScopes) - } - apiResource.Security[oidcOption.Name] = &resourcev1.ApiScopes{ - Scopes: oidcOption.Scopes, - } - } - } - // declare resource - result := <-defaultManager.registerResource(&resourcev1.ResourceDeclareRequest{ - Id: &resourcev1.ResourceIdentifier{ - Name: name, - Type: resourcev1.ResourceType_Api, - }, - Config: &resourcev1.ResourceDeclareRequest_Api{ - Api: apiResource, - }, - }) - if result.Err != nil { - return nil, result.Err - } - - return a, nil -} - -// Get adds a Get method handler to the path with any specified opts. -// Note: to chain middleware use handler.ComposeHttpMiddlware() -func (a *api) Get(match string, handler handler.HttpMiddleware, opts ...MethodOption) { - r := a.NewRoute(match) - - r.Get(handler, opts...) - a.routes[match] = r -} - -// Post adds a Post method handler to the path with any specified opts. -// Note: to chain middleware use handler.ComposeHttpMiddlware() -func (a *api) Post(match string, handler handler.HttpMiddleware, opts ...MethodOption) { - r := a.NewRoute(match) - - r.Post(handler, opts...) - a.routes[match] = r -} - -// Patch adds a Patch method handler to the path with any specified opts. -// Note: to chain middleware use handler.ComposeHttpMiddlware() -func (a *api) Patch(match string, handler handler.HttpMiddleware, opts ...MethodOption) { - r := a.NewRoute(match) - - r.Patch(handler, opts...) - a.routes[match] = r -} - -// Put adds a Put method handler to the path with any specified opts. -// Note: to chain middleware use handler.ComposeHttpMiddlware() -func (a *api) Put(match string, handler handler.HttpMiddleware, opts ...MethodOption) { - r := a.NewRoute(match) - - r.Put(handler, opts...) - a.routes[match] = r -} - -// Delete adds a Delete method handler to the path with any specified opts. -// Note: to chain middleware use handler.ComposeHttpMiddlware() -func (a *api) Delete(match string, handler handler.HttpMiddleware, opts ...MethodOption) { - r := a.NewRoute(match) - - r.Delete(handler, opts...) - a.routes[match] = r -} - -// Options adds an Options method handler to the path with any specified opts. -// Note: to chain middleware use handler.ComposeHttpMiddlware() -func (a *api) Options(match string, handler handler.HttpMiddleware, opts ...MethodOption) { - r := a.NewRoute(match) - - r.Options(handler, opts...) - a.routes[match] = r -} diff --git a/nitric/api_test.go b/nitric/api_test.go deleted file mode 100644 index f3a5cc5..0000000 --- a/nitric/api_test.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package nitric - -// import ( -// "context" - -// "github.com/golang/mock/gomock" -// . "github.com/onsi/ginkgo" -// . "github.com/onsi/gomega" - -// "github.com/nitrictech/go-sdk/faas" -// mock_v1 "github.com/nitrictech/go-sdk/mocks" -// v1 "github.com/nitrictech/nitric/core/pkg/api/nitric/v1" -// ) - -// var _ = Describe("api", func() { -// Context("New", func() { -// It("can register one method per routes", func() { -// m := &manager{ -// workers: map[string]Starter{}, -// builders: map[string]faas.HandlerBuilder{}, -// } -// a := &api{ -// name: "testApi", -// routes: map[string]Route{}, -// manager: m, -// } -// a.Get("objects/", func(hc *faas.HttpContext, hh faas.HttpHandler) (*faas.HttpContext, error) { return hc, nil }) -// a.Post("objects/", func(hc *faas.HttpContext, hh faas.HttpHandler) (*faas.HttpContext, error) { return hc, nil }) -// a.Get("objects/:id", func(hc *faas.HttpContext, hh faas.HttpHandler) (*faas.HttpContext, error) { return hc, nil }) -// a.Put("objects/:id", func(hc *faas.HttpContext, hh faas.HttpHandler) (*faas.HttpContext, error) { return hc, nil }) -// a.Patch("objects/:id", func(hc *faas.HttpContext, hh faas.HttpHandler) (*faas.HttpContext, error) { return hc, nil }) -// a.Delete("objects/:id", func(hc *faas.HttpContext, hh faas.HttpHandler) (*faas.HttpContext, error) { return hc, nil }) -// a.Options("objects/:id", func(hc *faas.HttpContext, hh faas.HttpHandler) (*faas.HttpContext, error) { return hc, nil }) - -// Expect(m.workers["route:testApi/objects/GET"]).ToNot(BeNil()) -// Expect(m.workers["route:testApi/objects/POST"]).ToNot(BeNil()) -// Expect(m.workers["route:testApi/objects/:id/GET"]).ToNot(BeNil()) -// Expect(m.workers["route:testApi/objects/:id/PUT"]).ToNot(BeNil()) -// Expect(m.workers["route:testApi/objects/:id/DELETE"]).ToNot(BeNil()) -// Expect(m.workers["route:testApi/objects/:id/OPTIONS"]).ToNot(BeNil()) -// }) -// It("can get api details", func() { -// ctrl := gomock.NewController(GinkgoT()) -// mockClient := mock_v1.NewMockResourceServiceClient(ctrl) -// mockConn := mock_v1.NewMockClientConnInterface(ctrl) -// m := &manager{ -// workers: map[string]Starter{}, -// builders: map[string]faas.HandlerBuilder{}, -// rsc: mockClient, -// conn: mockConn, -// } - -// mockClient.EXPECT().Details(gomock.Any(), &v1.ResourceDetailsRequest{ -// Resource: &v1.Resource{ -// Name: "testApi", -// Type: v1.ResourceType_Api, -// }, -// }).Return(&v1.ResourceDetailsResponse{ -// Id: "1234", -// Provider: "aws", -// Service: "lambda", -// Details: &v1.ResourceDetailsResponse_Api{ -// Api: &v1.ApiResourceDetails{ -// Url: "example.com/aws/thing", -// }, -// }, -// }, nil) -// a := &api{ -// name: "testApi", -// routes: map[string]Route{}, -// manager: m, -// } -// ad, err := a.Details(context.TODO()) -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(ad).To(Equal(&ApiDetails{ -// Details: Details{ -// ID: "1234", -// Provider: "aws", -// Service: "lambda", -// }, -// URL: "example.com/aws/thing", -// })) -// }) -// }) - -// Context("New With Security", func() { -// It("declares a new API resource with security rules", func() { -// ctrl := gomock.NewController(GinkgoT()) -// mockClient := mock_v1.NewMockResourceServiceClient(ctrl) -// mockConn := mock_v1.NewMockClientConnInterface(ctrl) -// m := &manager{ -// workers: map[string]Starter{}, -// builders: map[string]faas.HandlerBuilder{}, -// rsc: mockClient, -// conn: mockConn, -// } - -// mockClient.EXPECT().Declare(context.TODO(), &v1.ResourceDeclareRequest{ -// Resource: &v1.Resource{ -// Type: v1.ResourceType_Api, -// Name: "testApi", -// }, Config: &v1.ResourceDeclareRequest_Api{ -// Api: &v1.ApiResource{ -// SecurityDefinitions: map[string]*v1.ApiSecurityDefinition{ -// "jwt": { -// Definition: &v1.ApiSecurityDefinition_Jwt{ -// Jwt: &v1.ApiSecurityDefinitionJwt{ -// Audiences: []string{"test"}, -// Issuer: "https://test.com", -// }, -// }, -// }, -// }, -// Security: map[string]*v1.ApiScopes{ -// "jwt": { -// Scopes: []string{}, -// }, -// }, -// }, -// }, -// }).Times(1) - -// a, err := m.newApi("testApi", WithSecurityJwtRule("jwt", JwtSecurityRule{ -// Audiences: []string{"test"}, -// Issuer: "https://test.com", -// }), WithSecurity("jwt", []string{})) - -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(a).ToNot(BeNil()) - -// ctrl.Finish() -// }) -// }) -// }) diff --git a/nitric/apis/api.go b/nitric/apis/api.go new file mode 100644 index 0000000..1f2b381 --- /dev/null +++ b/nitric/apis/api.go @@ -0,0 +1,343 @@ +// Copyright 2021 Nitric Technologies Pty Ltd. +// +// 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. + +package apis + +import ( + "net/http" + "path" + "strings" + + "github.com/nitrictech/go-sdk/internal/handlers" + resources "github.com/nitrictech/go-sdk/nitric/resource" + "github.com/nitrictech/go-sdk/nitric/workers" + resourcev1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" + + apispb "github.com/nitrictech/nitric/core/pkg/proto/apis/v1" +) + +// Route providers convenience functions to register a handler in a single method. +type Route interface { + // All adds a handler for all HTTP methods to the route. + All(handler interface{}, opts ...MethodOption) + // Get adds a Get method handler to the route. + Get(handler interface{}, opts ...MethodOption) + // Put adds a Put method handler to the route. + Patch(handler interface{}, opts ...MethodOption) + // Patch adds a Patch method handler to the route. + Put(handler interface{}, opts ...MethodOption) + // Post adds a Post method handler to the route. + Post(handler interface{}, opts ...MethodOption) + // Delete adds a Delete method handler to the route. + Delete(handler interface{}, opts ...MethodOption) + // Options adds an Options method handler to the route. + Options(handler interface{}, opts ...MethodOption) + // ApiName returns the name of the API this route belongs to. + ApiName() string +} + +type Handler = handlers.Handler[Ctx] +type Middleware = handlers.Middleware[Ctx] + +type route struct { + path string + api *api + manager *workers.Manager + middleware Middleware +} + +func (a *api) NewRoute(match string, opts ...RouteOption) Route { + r, ok := a.routes[match] + if !ok { + r = &route{ + manager: a.manager, + path: path.Join(a.path, match), + api: a, + } + } + + for _, o := range opts { + o(r.(*route)) + } + + return r +} + +func (r *route) ApiName() string { + return r.api.name +} + +func (r *route) AddMethodHandler(methods []string, handler interface{}, opts ...MethodOption) error { + bName := path.Join(r.api.name, r.path, strings.Join(methods, "-")) + + // default methodOptions will contain OidcOptions passed to API instance and securityDisabled to false + mo := &methodOptions{ + securityDisabled: false, + security: r.api.security, + } + + for _, o := range opts { + o(mo) + } + + typedHandler, err := handlers.HandlerFromInterface[Ctx](handler) + if err != nil { + panic(err) + } + + apiOpts := &apispb.ApiWorkerOptions{ + SecurityDisabled: mo.securityDisabled, + Security: map[string]*apispb.ApiWorkerScopes{}, + } + + if mo.security != nil && !mo.securityDisabled { + for _, oidcOption := range mo.security { + err := attachOidc(r.api.name, oidcOption, r.manager) + if err != nil { + return err + } + + apiOpts.Security[oidcOption.Name] = &apispb.ApiWorkerScopes{ + Scopes: oidcOption.Scopes, + } + } + } + + registrationRequest := &apispb.RegistrationRequest{ + Path: r.path, + Api: r.api.name, + Methods: methods, + Options: apiOpts, + } + + if r.middleware != nil { + typedHandler = r.middleware(typedHandler) + } + + if r.api.middleware != nil { + typedHandler = r.api.middleware(typedHandler) + } + + wkr := newApiWorker(&apiWorkerOpts{ + RegistrationRequest: registrationRequest, + Handler: typedHandler, + }) + + r.manager.AddWorker("route:"+bName, wkr) + + return nil +} + +func (r *route) All(handler interface{}, opts ...MethodOption) { + _ = r.AddMethodHandler([]string{http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete, http.MethodOptions}, handler, opts...) +} + +func (r *route) Get(handler interface{}, opts ...MethodOption) { + _ = r.AddMethodHandler([]string{http.MethodGet}, handler, opts...) +} + +func (r *route) Post(handler interface{}, opts ...MethodOption) { + _ = r.AddMethodHandler([]string{http.MethodPost}, handler, opts...) +} + +func (r *route) Put(handler interface{}, opts ...MethodOption) { + _ = r.AddMethodHandler([]string{http.MethodPut}, handler, opts...) +} + +func (r *route) Patch(handler interface{}, opts ...MethodOption) { + _ = r.AddMethodHandler([]string{http.MethodPatch}, handler, opts...) +} + +func (r *route) Delete(handler interface{}, opts ...MethodOption) { + _ = r.AddMethodHandler([]string{http.MethodDelete}, handler, opts...) +} + +func (r *route) Options(handler interface{}, opts ...MethodOption) { + _ = r.AddMethodHandler([]string{http.MethodOptions}, handler, opts...) +} + +// Api Resource represents an HTTP API, capable of routing and securing incoming HTTP requests to handlers. +// path is the route path matcher e.g. '/home'. Supports path params via colon prefix e.g. '/customers/:customerId' +// handler the handler to register for callbacks. +type Api interface { + // Get adds a Get method handler to the path with any specified opts. + // Valid function signatures: + // + // func() + // func() error + // func(*apis.Ctx) + // func(*apis.Ctx) error + // Handler[apis.Ctx] + Get(path string, handler interface{}, opts ...MethodOption) + // Put adds a Put method handler to the path with any specified opts. + // Valid function signatures: + // + // func() + // func() error + // func(*apis.Ctx) + // func(*apis.Ctx) error + // Handler[apis.Ctx] + Put(path string, handler interface{}, opts ...MethodOption) + // Patch adds a Patch method handler to the path with any specified opts. + // Valid function signatures: + // + // func() + // func() error + // func(*apis.Ctx) + // func(*apis.Ctx) error + // Handler[apis.Ctx] + Patch(path string, handler interface{}, opts ...MethodOption) + // Post adds a Post method handler to the path with any specified opts. + // Valid function signatures: + // + // func() + // func() error + // func(*apis.Ctx) + // func(*apis.Ctx) error + // Handler[apis.Ctx] + Post(path string, handler interface{}, opts ...MethodOption) + // Delete adds a Delete method handler to the path with any specified opts. + // Valid function signatures: + // + // func() + // func() error + // func(*apis.Ctx) + // func(*apis.Ctx) error + // Handler[apis.Ctx] + Delete(path string, handler interface{}, opts ...MethodOption) + // Options adds a Options method handler to the path with any specified opts. + // Valid function signatures: + // + // func() + // func() error + // func(*apis.Ctx) + // func(*apis.Ctx) error + // Handler[apis.Ctx] + Options(path string, handler interface{}, opts ...MethodOption) + // NewRoute creates a new Route object for the given path. + NewRoute(path string, opts ...RouteOption) Route +} + +type ApiDetails struct { + resources.Details + URL string +} + +type api struct { + name string + routes map[string]Route + manager *workers.Manager + securityRules map[string]interface{} + security []OidcOptions + path string + middleware Middleware +} + +// Get adds a Get method handler to the path with any specified opts. +func (a *api) Get(match string, handler interface{}, opts ...MethodOption) { + r := a.NewRoute(match) + + r.Get(handler, opts...) + a.routes[match] = r +} + +// Post adds a Post method handler to the path with any specified opts. +func (a *api) Post(match string, handler interface{}, opts ...MethodOption) { + r := a.NewRoute(match) + + r.Post(handler, opts...) + a.routes[match] = r +} + +// Patch adds a Patch method handler to the path with any specified opts. +func (a *api) Patch(match string, handler interface{}, opts ...MethodOption) { + r := a.NewRoute(match) + + r.Patch(handler, opts...) + a.routes[match] = r +} + +// Put adds a Put method handler to the path with any specified opts. +func (a *api) Put(match string, handler interface{}, opts ...MethodOption) { + r := a.NewRoute(match) + + r.Put(handler, opts...) + a.routes[match] = r +} + +// Delete adds a Delete method handler to the path with any specified opts. +func (a *api) Delete(match string, handler interface{}, opts ...MethodOption) { + r := a.NewRoute(match) + + r.Delete(handler, opts...) + a.routes[match] = r +} + +// Options adds an Options method handler to the path with any specified opts. +func (a *api) Options(match string, handler interface{}, opts ...MethodOption) { + r := a.NewRoute(match) + + r.Options(handler, opts...) + a.routes[match] = r +} + +// NewApi Registers a new API Resource. +// +// The returned API object can be used to register Routes and Methods, with Handlers. +func NewApi(name string, opts ...ApiOption) Api { + a := &api{ + name: name, + routes: map[string]Route{}, + manager: workers.GetDefaultManager(), + } + + // Apply options + for _, o := range opts { + o(a) + } + + apiResource := &resourcev1.ApiResource{} + + // Attaching OIDC Options to API + if a.security != nil { + for _, oidcOption := range a.security { + err := attachOidc(a.name, oidcOption, a.manager) + if err != nil { + panic(err) + } + + if apiResource.GetSecurity() == nil { + apiResource.Security = make(map[string]*resourcev1.ApiScopes) + } + apiResource.Security[oidcOption.Name] = &resourcev1.ApiScopes{ + Scopes: oidcOption.Scopes, + } + } + } + // declare resource + result := <-a.manager.RegisterResource(&resourcev1.ResourceDeclareRequest{ + Id: &resourcev1.ResourceIdentifier{ + Name: name, + Type: resourcev1.ResourceType_Api, + }, + Config: &resourcev1.ResourceDeclareRequest_Api{ + Api: apiResource, + }, + }) + if result.Err != nil { + panic(result.Err) + } + + return a +} diff --git a/nitric/apis/context.go b/nitric/apis/context.go new file mode 100644 index 0000000..b9a3c7f --- /dev/null +++ b/nitric/apis/context.go @@ -0,0 +1,89 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package apis + +import ( + "net/textproto" + + apispb "github.com/nitrictech/nitric/core/pkg/proto/apis/v1" +) + +type Ctx struct { + id string + Request Request + Response *Response + Extras map[string]interface{} +} + +func (c *Ctx) ToClientMessage() *apispb.ClientMessage { + headers := make(map[string]*apispb.HeaderValue) + for k, v := range c.Response.Headers { + headers[k] = &apispb.HeaderValue{ + Value: v, + } + } + + return &apispb.ClientMessage{ + Id: c.id, + Content: &apispb.ClientMessage_HttpResponse{ + HttpResponse: &apispb.HttpResponse{ + Status: int32(c.Response.Status), + Headers: headers, + Body: c.Response.Body, + }, + }, + } +} + +func NewCtx(msg *apispb.ServerMessage) *Ctx { + req := msg.GetHttpRequest() + + headers := make(textproto.MIMEHeader) + for k, v := range req.Headers { + headers[k] = v.GetValue() + } + + query := make(map[string][]string) + for k, v := range req.QueryParams { + query[k] = v.GetValue() + } + + return &Ctx{ + id: msg.Id, + Request: &HttpRequest{ + method: req.Method, + path: req.Path, + pathParams: req.PathParams, + query: query, + headers: headers, + data: req.Body, + }, + Response: &Response{ + Status: 200, + Headers: map[string][]string{}, + Body: nil, + }, + } +} + +func (c *Ctx) WithError(err error) { + c.Response = &Response{ + Status: 500, + Headers: map[string][]string{ + "Content-Type": {"text/plain"}, + }, + Body: []byte("Internal Server Error"), + } +} diff --git a/nitric/oidc.go b/nitric/apis/oidc.go similarity index 79% rename from nitric/oidc.go rename to nitric/apis/oidc.go index 8edea02..1065567 100644 --- a/nitric/oidc.go +++ b/nitric/apis/oidc.go @@ -12,9 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -package nitric +package apis import ( + "github.com/nitrictech/go-sdk/nitric/workers" v1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" ) @@ -25,8 +26,8 @@ type OidcOptions struct { Scopes []string } -func attachOidc(apiName string, options OidcOptions) error { - _, err := NewOidcSecurityDefinition(apiName, options) +func attachOidc(apiName string, options OidcOptions, manager *workers.Manager) error { + _, err := newOidcSecurityDefinition(apiName, options, manager) if err != nil { return err } @@ -45,20 +46,20 @@ type oidcSecurityDefinition struct { Issuer string Audiences []string - manager Manager + manager *workers.Manager } -func NewOidcSecurityDefinition(apiName string, options OidcOptions) (OidcSecurityDefinition, error) { +func newOidcSecurityDefinition(apiName string, options OidcOptions, manager *workers.Manager) (OidcSecurityDefinition, error) { o := &oidcSecurityDefinition{ ApiName: apiName, RuleName: options.Name, Issuer: options.Issuer, Audiences: options.Audiences, - manager: defaultManager, + manager: manager, } // declare resource - registerResult := <-defaultManager.registerResource(&v1.ResourceDeclareRequest{ + registerResult := <-manager.RegisterResource(&v1.ResourceDeclareRequest{ Id: &v1.ResourceIdentifier{ Name: options.Name, Type: v1.ResourceType_ApiSecurityDefinition, diff --git a/nitric/options.go b/nitric/apis/options.go similarity index 77% rename from nitric/options.go rename to nitric/apis/options.go index d74094b..bbaf790 100644 --- a/nitric/options.go +++ b/nitric/apis/options.go @@ -12,15 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package nitric - -import ( - "github.com/nitrictech/go-sdk/handler" -) +package apis type ( - ApiOption = func(api *api) - MethodOption = func(mo *methodOptions) + ApiOption func(api *api) + RouteOption func(route Route) + MethodOption func(mo *methodOptions) ) type JwtSecurityRule struct { @@ -33,6 +30,13 @@ type methodOptions struct { securityDisabled bool } +// WithMiddleware - Apply a middleware function to all handlers in the API +func WithMiddleware(middleware Middleware) ApiOption { + return func(api *api) { + api.middleware = middleware + } +} + func OidcRule(name string, issuer string, audiences []string) SecurityOption { return func(scopes []string) OidcOptions { return OidcOptions{ @@ -44,16 +48,7 @@ func OidcRule(name string, issuer string, audiences []string) SecurityOption { } } -func WithMiddleware(middleware ...handler.HttpMiddleware) ApiOption { - return func(api *api) { - if api.middleware != nil { - api.middleware = handler.ComposeHttpMiddleware(api.middleware, handler.ComposeHttpMiddleware(middleware...)) - } else { - api.middleware = handler.ComposeHttpMiddleware(middleware...) - } - } -} - +// WithSecurityJwtRule - Apply a JWT security rule to the API func WithSecurityJwtRule(name string, rule JwtSecurityRule) ApiOption { return func(api *api) { if api.securityRules == nil { @@ -64,6 +59,7 @@ func WithSecurityJwtRule(name string, rule JwtSecurityRule) ApiOption { } } +// WithSecurity - Apply security settings to the API func WithSecurity(oidcOptions OidcOptions) ApiOption { return func(api *api) { if api.security == nil { @@ -74,19 +70,21 @@ func WithSecurity(oidcOptions OidcOptions) ApiOption { } } -// WithPath - Prefixes API with the given path +// WithPath - Set the base path for the API func WithPath(path string) ApiOption { return func(api *api) { api.path = path } } +// WithNoMethodSecurity - Disable security for a method func WithNoMethodSecurity() MethodOption { return func(mo *methodOptions) { mo.securityDisabled = true } } +// WithMethodSecurity - Override/set the security settings for a method func WithMethodSecurity(oidcOptions OidcOptions) MethodOption { return func(mo *methodOptions) { mo.securityDisabled = false diff --git a/nitric/apis/request.go b/nitric/apis/request.go new file mode 100644 index 0000000..b69b87d --- /dev/null +++ b/nitric/apis/request.go @@ -0,0 +1,59 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package apis + +import "net/textproto" + +type Request interface { + Method() string + Path() string + Data() []byte + Query() map[string][]string + Headers() textproto.MIMEHeader + PathParams() map[string]string +} + +type HttpRequest struct { + method string + path string + data []byte + query map[string][]string + headers textproto.MIMEHeader + pathParams map[string]string +} + +func (h *HttpRequest) Method() string { + return h.method +} + +func (h *HttpRequest) Path() string { + return h.path +} + +func (h *HttpRequest) Data() []byte { + return h.data +} + +func (h *HttpRequest) Query() map[string][]string { + return h.query +} + +func (h *HttpRequest) Headers() textproto.MIMEHeader { + return h.headers +} + +func (h *HttpRequest) PathParams() map[string]string { + return h.pathParams +} diff --git a/handler/response.go b/nitric/apis/response.go similarity index 59% rename from handler/response.go rename to nitric/apis/response.go index 7eb8c98..9ddc028 100644 --- a/handler/response.go +++ b/nitric/apis/response.go @@ -1,10 +1,10 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. +// Copyright 2023 Nitric Technologies Pty Ltd. // // 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 +// 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, @@ -12,30 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -package handler +package apis -type HttpResponse struct { +type Response struct { Status int Headers map[string][]string Body []byte } - -type MessageResponse struct { - Success bool -} - -type IntervalResponse struct { - Success bool -} - -type BlobEventResponse struct { - Success bool -} - -type FileEventResponse struct { - Success bool -} - -type WebsocketResponse struct { - Reject bool -} diff --git a/workers/api.go b/nitric/apis/workers.go similarity index 64% rename from workers/api.go rename to nitric/apis/workers.go index fb0b398..0305b98 100644 --- a/workers/api.go +++ b/nitric/apis/workers.go @@ -12,37 +12,36 @@ // See the License for the specific language governing permissions and // limitations under the License. -package workers +package apis import ( "context" - "fmt" + errorsstd "errors" "io" - "google.golang.org/grpc" - - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" - "github.com/nitrictech/go-sdk/constants" - "github.com/nitrictech/go-sdk/handler" + grpcx "github.com/nitrictech/go-sdk/internal/grpc" + "github.com/nitrictech/go-sdk/internal/handlers" + "github.com/nitrictech/go-sdk/nitric/errors" + "github.com/nitrictech/go-sdk/nitric/errors/codes" + "github.com/nitrictech/go-sdk/nitric/workers" v1 "github.com/nitrictech/nitric/core/pkg/proto/apis/v1" ) -type ApiWorker struct { +type apiWorker struct { client v1.ApiClient - middleware handler.HttpMiddleware + Handler handlers.Handler[Ctx] registrationRequest *v1.RegistrationRequest } -type ApiWorkerOpts struct { +type apiWorkerOpts struct { RegistrationRequest *v1.RegistrationRequest - Middleware handler.HttpMiddleware + Handler handlers.Handler[Ctx] } -var _ Worker = (*ApiWorker)(nil) +var _ workers.StreamWorker = (*apiWorker)(nil) // Start implements Worker. -func (a *ApiWorker) Start(ctx context.Context) error { +func (a *apiWorker) Start(ctx context.Context) error { initReq := &v1.ClientMessage{ Content: &v1.ClientMessage_RegistrationRequest{ RegistrationRequest: a.registrationRequest, @@ -60,11 +59,11 @@ func (a *ApiWorker) Start(ctx context.Context) error { } for { - var ctx *handler.HttpContext + var ctx *Ctx resp, err := stream.Recv() - if err == io.EOF { + if errorsstd.Is(err, io.EOF) { err = stream.CloseSend() if err != nil { return err @@ -72,12 +71,11 @@ func (a *ApiWorker) Start(ctx context.Context) error { return nil } else if err == nil && resp.GetRegistrationResponse() != nil { - // Function connected with Nitric server - fmt.Println("Function connected with Nitric server") + // There is no need to respond to the registration response } else if err == nil && resp.GetHttpRequest() != nil { - ctx = handler.NewHttpContext(resp) + ctx = NewCtx(resp) - ctx, err = a.middleware(ctx, handler.HttpDummy) + err = a.Handler(ctx) if err != nil { ctx.WithError(err) } @@ -92,14 +90,8 @@ func (a *ApiWorker) Start(ctx context.Context) error { } } -func NewApiWorker(opts *ApiWorkerOpts) *ApiWorker { - ctx, _ := context.WithTimeout(context.TODO(), constants.NitricDialTimeout()) - - conn, err := grpc.DialContext( - ctx, - constants.NitricAddress(), - constants.DefaultOptions()..., - ) +func newApiWorker(opts *apiWorkerOpts) *apiWorker { + conn, err := grpcx.GetConnection() if err != nil { panic(errors.NewWithCause( codes.Unavailable, @@ -110,9 +102,9 @@ func NewApiWorker(opts *ApiWorkerOpts) *ApiWorker { client := v1.NewApiClient(conn) - return &ApiWorker{ + return &apiWorker{ client: client, registrationRequest: opts.RegistrationRequest, - middleware: opts.Middleware, + Handler: opts.Handler, } } diff --git a/nitric/bucket_test.go b/nitric/bucket_test.go deleted file mode 100644 index d320751..0000000 --- a/nitric/bucket_test.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package nitric - -// import ( -// "context" - -// . "github.com/onsi/ginkgo" -// . "github.com/onsi/gomega" - -// "github.com/golang/mock/gomock" - -// mock_v1 "github.com/nitrictech/go-sdk/mocks" -// "github.com/nitrictech/go-sdk/mocks/mockapi" -// v1 "github.com/nitrictech/nitric/core/pkg/api/nitric/v1" -// ) - -// var _ = Describe("bucket", func() { -// ctrl := gomock.NewController(GinkgoT()) -// Context("New", func() { -// mockConn := mock_v1.NewMockClientConnInterface(ctrl) -// When("valid args", func() { -// mockClient := mock_v1.NewMockResourceServiceClient(ctrl) -// mockStorage := mockapi.NewMockStorage(ctrl) - -// m := &manager{ -// workers: map[string]Starter{}, -// conn: mockConn, -// rsc: mockClient, -// storage: mockStorage, -// } - -// mockClient.EXPECT().Declare(context.Background(), -// &v1.ResourceDeclareRequest{ -// Resource: &v1.Resource{ -// Type: v1.ResourceType_Bucket, -// Name: "red", -// }, -// Config: &v1.ResourceDeclareRequest_Bucket{ -// Bucket: &v1.BucketResource{}, -// }, -// }) - -// mockClient.EXPECT().Declare(context.Background(), -// &v1.ResourceDeclareRequest{ -// Resource: &v1.Resource{ -// Type: v1.ResourceType_Policy, -// }, -// Config: &v1.ResourceDeclareRequest_Policy{ -// Policy: &v1.PolicyResource{ -// Principals: []*v1.Resource{{ -// Type: v1.ResourceType_Function, -// }}, -// Actions: []v1.Action{ -// v1.Action_BucketFileGet, v1.Action_BucketFileList, v1.Action_BucketFilePut, -// }, -// Resources: []*v1.Resource{{ -// Type: v1.ResourceType_Bucket, -// Name: "red", -// }}, -// }, -// }, -// }) - -// mockBucket := mockapi.NewMockBucket(ctrl) -// mockStorage.EXPECT().Bucket("red").Return(mockBucket) -// b, err := m.newBucket("red", BucketReading, BucketWriting) - -// It("should not return an error", func() { -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(b).ShouldNot(BeNil()) -// }) -// }) -// }) -// }) diff --git a/nitric/common.go b/nitric/common.go deleted file mode 100644 index 4b95940..0000000 --- a/nitric/common.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package nitric - -import ( - nitricv1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" -) - -func functionResourceDeclareRequest(subject *nitricv1.ResourceIdentifier, actions []nitricv1.Action) *nitricv1.ResourceDeclareRequest { - return &nitricv1.ResourceDeclareRequest{ - Id: &nitricv1.ResourceIdentifier{ - Type: nitricv1.ResourceType_Policy, - }, - Config: &nitricv1.ResourceDeclareRequest_Policy{ - Policy: &nitricv1.PolicyResource{ - Principals: []*nitricv1.ResourceIdentifier{ - { - Type: nitricv1.ResourceType_Service, - }, - }, - Actions: actions, - Resources: []*nitricv1.ResourceIdentifier{subject}, - }, - }, - } -} - -type Details struct { - // The identifier of the resource - ID string - // The provider this resource is deployed with (e.g. aws) - Provider string - // The service this resource is deployed on (e.g. ApiGateway) - Service string -} diff --git a/api/errors/api_error.go b/nitric/errors/api_error.go similarity index 97% rename from api/errors/api_error.go rename to nitric/errors/api_error.go index d583812..c688d2c 100644 --- a/api/errors/api_error.go +++ b/nitric/errors/api_error.go @@ -21,7 +21,7 @@ import ( multierror "github.com/missionMeteora/toolkit/errors" "google.golang.org/grpc/status" - "github.com/nitrictech/go-sdk/api/errors/codes" + "github.com/nitrictech/go-sdk/nitric/errors/codes" ) type ApiError struct { diff --git a/api/errors/codes/codes.go b/nitric/errors/codes/codes.go similarity index 100% rename from api/errors/codes/codes.go rename to nitric/errors/codes/codes.go diff --git a/api/keyvalue/store.go b/nitric/keyvalue/client.go similarity index 70% rename from api/keyvalue/store.go rename to nitric/keyvalue/client.go index e745297..f688f18 100644 --- a/api/keyvalue/store.go +++ b/nitric/keyvalue/client.go @@ -17,8 +17,9 @@ package keyvalue import ( "context" - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" + grpcx "github.com/nitrictech/go-sdk/internal/grpc" + "github.com/nitrictech/go-sdk/nitric/errors" + "github.com/nitrictech/go-sdk/nitric/errors/codes" "github.com/nitrictech/protoutils" v1 "github.com/nitrictech/nitric/core/pkg/proto/kvstore/v1" @@ -49,29 +50,29 @@ func (k *KeyStream) Recv() (string, error) { return resp.Key, nil } -type Store interface { +type KvStoreClientIface interface { // Name - The name of the store Name() string // Get a value from the store - Get(context.Context, string) (map[string]interface{}, error) + Get(ctx context.Context, key string) (map[string]interface{}, error) // Set a value in the store - Set(context.Context, string, map[string]interface{}) error + Set(ctx context.Context, key string, value map[string]interface{}) error // Delete a value from the store - Delete(context.Context, string) error + Delete(ctx context.Context, key string) error // Return an async iterable of keys in the store - Keys(context.Context, ...ScanKeysOption) (*KeyStream, error) + Keys(ctx context.Context, options ...ScanKeysOption) (*KeyStream, error) } -type storeImpl struct { +type KvStoreClient struct { name string kvClient v1.KvStoreClient } -func (s *storeImpl) Name() string { +func (s *KvStoreClient) Name() string { return s.name } -func (s *storeImpl) Get(ctx context.Context, key string) (map[string]interface{}, error) { +func (s *KvStoreClient) Get(ctx context.Context, key string) (map[string]interface{}, error) { ref := &v1.ValueRef{ Store: s.name, Key: key, @@ -93,7 +94,7 @@ func (s *storeImpl) Get(ctx context.Context, key string) (map[string]interface{} return content, nil } -func (s *storeImpl) Set(ctx context.Context, key string, value map[string]interface{}) error { +func (s *KvStoreClient) Set(ctx context.Context, key string, value map[string]interface{}) error { ref := &v1.ValueRef{ Store: s.name, Key: key, @@ -116,7 +117,7 @@ func (s *storeImpl) Set(ctx context.Context, key string, value map[string]interf return nil } -func (s *storeImpl) Delete(ctx context.Context, key string) error { +func (s *KvStoreClient) Delete(ctx context.Context, key string) error { ref := &v1.ValueRef{ Store: s.name, Key: key, @@ -132,7 +133,7 @@ func (s *storeImpl) Delete(ctx context.Context, key string) error { return nil } -func (s *storeImpl) Keys(ctx context.Context, opts ...ScanKeysOption) (*KeyStream, error) { +func (s *KvStoreClient) Keys(ctx context.Context, opts ...ScanKeysOption) (*KeyStream, error) { store := &v1.Store{ Name: s.name, } @@ -156,3 +157,21 @@ func (s *storeImpl) Keys(ctx context.Context, opts ...ScanKeysOption) (*KeyStrea stream: streamClient, }, nil } + +func NewKvStoreClient(name string) (*KvStoreClient, error) { + conn, err := grpcx.GetConnection() + if err != nil { + return nil, errors.NewWithCause( + codes.Unavailable, + "NewKvStoreClient: unable to reach nitric server", + err, + ) + } + + client := v1.NewKvStoreClient(conn) + + return &KvStoreClient{ + name: name, + kvClient: client, + }, nil +} diff --git a/api/keyvalue/store_test.go b/nitric/keyvalue/client_test.go similarity index 97% rename from api/keyvalue/store_test.go rename to nitric/keyvalue/client_test.go index 77fb16a..0ab7e35 100644 --- a/api/keyvalue/store_test.go +++ b/nitric/keyvalue/client_test.go @@ -32,17 +32,17 @@ var _ = Describe("KeyValue Store API", func() { var ( ctrl *gomock.Controller mockKV *mock_v1.MockKvStoreClient - kv *keyValueImpl - store Store + kv *KvStoreClient + store KvStoreClientIface storeName string ) BeforeEach(func() { ctrl = gomock.NewController(GinkgoT()) mockKV = mock_v1.NewMockKvStoreClient(ctrl) - kv = &keyValueImpl{kvClient: mockKV} storeName = "test-store" - store = kv.Store(storeName) + kv = &KvStoreClient{name: storeName, kvClient: mockKV} + store = kv }) AfterEach(func() { @@ -139,7 +139,6 @@ var _ = Describe("KeyValue Store API", func() { Expect(strings.Contains(err.Error(), errorMsg)).To(BeTrue()) }) }) - }) Describe("Delete", func() { diff --git a/nitric/keyvalue.go b/nitric/keyvalue/keyvalue.go similarity index 69% rename from nitric/keyvalue.go rename to nitric/keyvalue/keyvalue.go index 4ddffce..0eb9fe6 100644 --- a/nitric/keyvalue.go +++ b/nitric/keyvalue/keyvalue.go @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package nitric +package keyvalue import ( "fmt" - "github.com/nitrictech/go-sdk/api/keyvalue" + "github.com/nitrictech/go-sdk/nitric/workers" v1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" ) @@ -32,23 +32,25 @@ const ( var KvStoreEverything []KvStorePermission = []KvStorePermission{KvStoreSet, KvStoreGet, KvStoreDelete} type KvStore interface { - Allow(KvStorePermission, ...KvStorePermission) (keyvalue.Store, error) + // Allow requests the given permissions to the key/value store. + Allow(permission KvStorePermission, permissions ...KvStorePermission) KvStoreClientIface } type kvstore struct { name string - manager Manager - registerChan <-chan RegisterResult + manager *workers.Manager + registerChan <-chan workers.RegisterResult } +// NewKv - Create a new Key/Value store resource func NewKv(name string) *kvstore { kvstore := &kvstore{ name: name, - manager: defaultManager, - registerChan: make(chan RegisterResult), + manager: workers.GetDefaultManager(), + registerChan: make(chan workers.RegisterResult), } - kvstore.registerChan = defaultManager.registerResource(&v1.ResourceDeclareRequest{ + kvstore.registerChan = kvstore.manager.RegisterResource(&v1.ResourceDeclareRequest{ Id: &v1.ResourceIdentifier{ Type: v1.ResourceType_KeyValueStore, Name: name, @@ -61,8 +63,7 @@ func NewKv(name string) *kvstore { return kvstore } -// NewQueue registers this queue as a required resource for the calling function/container. -func (k *kvstore) Allow(permission KvStorePermission, permissions ...KvStorePermission) (keyvalue.Store, error) { +func (k *kvstore) Allow(permission KvStorePermission, permissions ...KvStorePermission) KvStoreClientIface { allPerms := append([]KvStorePermission{permission}, permissions...) actions := []v1.Action{} @@ -75,27 +76,25 @@ func (k *kvstore) Allow(permission KvStorePermission, permissions ...KvStorePerm case KvStoreDelete: actions = append(actions, v1.Action_KeyValueStoreDelete) default: - return nil, fmt.Errorf("KvStorePermission %s unknown", perm) + panic(fmt.Sprintf("KvStorePermission %s unknown", perm)) } } registerResult := <-k.registerChan if registerResult.Err != nil { - return nil, registerResult.Err + panic(registerResult.Err) } - m, err := k.manager.registerPolicy(registerResult.Identifier, actions...) + err := k.manager.RegisterPolicy(registerResult.Identifier, actions...) if err != nil { - return nil, err + panic(err) } - if m.kvstores == nil { - m.kvstores, err = keyvalue.New() - if err != nil { - return nil, err - } + client, err := NewKvStoreClient(k.name) + if err != nil { + panic(err) } - return m.kvstores.Store(k.name), nil + return client } diff --git a/api/keyvalue/keyvalue_suite_test.go b/nitric/keyvalue/keyvalue_suite_test.go similarity index 100% rename from api/keyvalue/keyvalue_suite_test.go rename to nitric/keyvalue/keyvalue_suite_test.go diff --git a/nitric/manager_test.go b/nitric/manager_test.go deleted file mode 100644 index 7b3cf42..0000000 --- a/nitric/manager_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package nitric - -// import ( -// "errors" -// "io" - -// . "github.com/onsi/ginkgo" -// . "github.com/onsi/gomega" - -// apierrors "github.com/nitrictech/go-sdk/api/errors" -// ) - -// var _ = Describe("manager", func() { -// Context("isEOF", func() { -// When("is nil", func() { -// got := isEOF(nil) -// It("should be false", func() { -// Expect(got).To(Equal(false)) -// }) -// }) - -// When("is EOF wrapped in ApiError", func() { -// err := apierrors.NewWithCause(500, "unknown", io.EOF) -// got := isEOF(err) -// It("should be true", func() { -// Expect(got).To(Equal(true)) -// }) -// }) - -// When("is an ApiError with nil cause", func() { -// err := apierrors.New(500, "unknown") -// got := isEOF(err) -// It("should be false", func() { -// Expect(got).To(Equal(false)) -// }) -// }) - -// When("is EOF string wrapped in ApiError", func() { -// err := apierrors.NewWithCause(500, "unknown", errors.New("EOF")) -// got := isEOF(err) -// It("should be true", func() { -// Expect(got).To(Equal(true)) -// }) -// }) - -// When("is unexpectedEOF wrapped in ApiError", func() { -// err := apierrors.NewWithCause(500, "unknown", io.ErrUnexpectedEOF) -// got := isEOF(err) -// It("should be false", func() { -// Expect(got).To(Equal(false)) -// }) -// }) - -// When("is native EOF", func() { -// got := isEOF(io.EOF) -// It("should be true", func() { -// Expect(got).To(Equal(true)) -// }) -// }) -// }) -// }) diff --git a/nitric/nitric.go b/nitric/nitric.go new file mode 100644 index 0000000..d2d5f53 --- /dev/null +++ b/nitric/nitric.go @@ -0,0 +1,47 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package nitric + +import ( + "github.com/nitrictech/go-sdk/nitric/apis" + "github.com/nitrictech/go-sdk/nitric/keyvalue" + "github.com/nitrictech/go-sdk/nitric/queues" + "github.com/nitrictech/go-sdk/nitric/schedules" + "github.com/nitrictech/go-sdk/nitric/secrets" + "github.com/nitrictech/go-sdk/nitric/sql" + "github.com/nitrictech/go-sdk/nitric/storage" + "github.com/nitrictech/go-sdk/nitric/topics" + "github.com/nitrictech/go-sdk/nitric/websockets" + "github.com/nitrictech/go-sdk/nitric/workers" +) + +var ( + NewApi = apis.NewApi + NewKv = keyvalue.NewKv + NewQueue = queues.NewQueue + NewSchedule = schedules.NewSchedule + NewSecret = secrets.NewSecret + NewSqlDatabase = sql.NewSqlDatabase + NewBucket = storage.NewBucket + NewTopic = topics.NewTopic + NewWebsocket = websockets.NewWebsocket +) + +func Run() { + err := workers.GetDefaultManager().Run() + if err != nil { + panic(err) + } +} diff --git a/nitric/queue_test.go b/nitric/queue_test.go deleted file mode 100644 index 1cb6091..0000000 --- a/nitric/queue_test.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package nitric - -// import ( -// "context" - -// . "github.com/onsi/ginkgo" -// . "github.com/onsi/gomega" - -// "github.com/golang/mock/gomock" - -// mock_v1 "github.com/nitrictech/go-sdk/mocks" -// "github.com/nitrictech/go-sdk/mocks/mockapi" -// nitricv1 "github.com/nitrictech/nitric/core/pkg/api/nitric/v1" -// ) - -// var _ = Describe("queue", func() { -// ctrl := gomock.NewController(GinkgoT()) -// Context("New", func() { -// mockConn := mock_v1.NewMockClientConnInterface(ctrl) -// When("valid args", func() { -// mockClient := mock_v1.NewMockResourceServiceClient(ctrl) -// mockQueues := mockapi.NewMockQueues(ctrl) - -// m := &manager{ -// workers: map[string]Starter{}, -// conn: mockConn, -// rsc: mockClient, -// queues: mockQueues, -// } - -// mockClient.EXPECT().Declare(context.Background(), -// &nitricv1.ResourceDeclareRequest{ -// Resource: &nitricv1.Resource{ -// Type: nitricv1.ResourceType_Queue, -// Name: "wollies", -// }, -// Config: &nitricv1.ResourceDeclareRequest_Queue{ -// Queue: &nitricv1.QueueResource{}, -// }, -// }) - -// mockClient.EXPECT().Declare(context.Background(), -// &nitricv1.ResourceDeclareRequest{ -// Resource: &nitricv1.Resource{ -// Type: nitricv1.ResourceType_Policy, -// }, -// Config: &nitricv1.ResourceDeclareRequest_Policy{ -// Policy: &nitricv1.PolicyResource{ -// Principals: []*nitricv1.Resource{{ -// Type: nitricv1.ResourceType_Function, -// }}, -// Actions: []nitricv1.Action{ -// nitricv1.Action_QueueReceive, -// nitricv1.Action_QueueDetail, -// nitricv1.Action_QueueList, -// }, -// Resources: []*nitricv1.Resource{{ -// Type: nitricv1.ResourceType_Queue, -// Name: "wollies", -// }}, -// }, -// }, -// }) - -// mockQueue := mockapi.NewMockQueue(ctrl) -// mockQueues.EXPECT().Queue("wollies").Return(mockQueue) -// b, err := m.newQueue("wollies", QueueReceiving) - -// It("should not return an error", func() { -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(b).ShouldNot(BeNil()) -// }) -// }) -// }) -// }) diff --git a/api/queues/queue.go b/nitric/queues/client.go similarity index 69% rename from api/queues/queue.go rename to nitric/queues/client.go index 93629bb..023e7db 100644 --- a/api/queues/queue.go +++ b/nitric/queues/client.go @@ -17,31 +17,32 @@ package queues import ( "context" - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" + grpcx "github.com/nitrictech/go-sdk/internal/grpc" + "github.com/nitrictech/go-sdk/nitric/errors" + "github.com/nitrictech/go-sdk/nitric/errors/codes" v1 "github.com/nitrictech/nitric/core/pkg/proto/queues/v1" ) -// Queue is a resource for async enqueueing/dequeueing of messages. -type Queue interface { +// QueueClientIface is a resource for async enqueueing/dequeueing of messages. +type QueueClientIface interface { // Name - The name of the queue Name() string // Enqueue - Push a number of messages to a queue - Enqueue(context.Context, []map[string]interface{}) ([]*FailedMessage, error) + Enqueue(ctx context.Context, messages []map[string]interface{}) ([]*FailedMessage, error) // Dequeue - Retrieve messages from a queue to a maximum of the given depth - Dequeue(context.Context, int) ([]ReceivedMessage, error) + Dequeue(ctx context.Context, depth int) ([]ReceivedMessage, error) } -type queueImpl struct { +type QueueClient struct { name string queueClient v1.QueuesClient } -func (q *queueImpl) Name() string { +func (q *QueueClient) Name() string { return q.name } -func (q *queueImpl) Dequeue(ctx context.Context, depth int) ([]ReceivedMessage, error) { +func (q *QueueClient) Dequeue(ctx context.Context, depth int) ([]ReceivedMessage, error) { if depth < 1 { return nil, errors.New(codes.InvalidArgument, "Queue.Dequeue: depth cannot be less than 1") } @@ -57,7 +58,7 @@ func (q *queueImpl) Dequeue(ctx context.Context, depth int) ([]ReceivedMessage, rts := make([]ReceivedMessage, len(r.GetMessages())) for i, message := range r.GetMessages() { - rts[i] = &receivedMessageImpl{ + rts[i] = &leasedMessage{ queueName: q.name, queueClient: q.queueClient, leaseId: message.GetLeaseId(), @@ -68,7 +69,7 @@ func (q *queueImpl) Dequeue(ctx context.Context, depth int) ([]ReceivedMessage, return rts, nil } -func (q *queueImpl) Enqueue(ctx context.Context, messages []map[string]interface{}) ([]*FailedMessage, error) { +func (q *QueueClient) Enqueue(ctx context.Context, messages []map[string]interface{}) ([]*FailedMessage, error) { // Convert SDK Message objects to gRPC Message objects wireMessages := make([]*v1.QueueMessage, len(messages)) for i, message := range messages { @@ -103,3 +104,21 @@ func (q *queueImpl) Enqueue(ctx context.Context, messages []map[string]interface return failedMessages, nil } + +func NewQueueClient(name string) (*QueueClient, error) { + conn, err := grpcx.GetConnection() + if err != nil { + return nil, errors.NewWithCause( + codes.Unavailable, + "NewQueueClient: unable to reach nitric server", + err, + ) + } + + queueClient := v1.NewQueuesClient(conn) + + return &QueueClient{ + name: name, + queueClient: queueClient, + }, nil +} diff --git a/api/queues/queue_test.go b/nitric/queues/client_test.go similarity index 95% rename from api/queues/queue_test.go rename to nitric/queues/client_test.go index f0107c6..a3e35b5 100644 --- a/api/queues/queue_test.go +++ b/nitric/queues/client_test.go @@ -32,20 +32,19 @@ var _ = Describe("Queue interface", func() { var ( ctrl *gomock.Controller mockQ *mock_v1.MockQueuesClient - queues *queuesImpl queueName string - q Queue + q QueueClientIface ctx context.Context ) BeforeEach(func() { ctrl = gomock.NewController(GinkgoT()) mockQ = mock_v1.NewMockQueuesClient(ctrl) - queues = &queuesImpl{ + queueName = "test-queue" + q = &QueueClient{ queueClient: mockQ, + name: queueName, } - queueName = "test-queue" - q = queues.Queue(queueName) ctx = context.Background() }) @@ -110,7 +109,7 @@ var _ = Describe("Queue interface", func() { ).Times(1) }) - It("should recieve a message from []*FailedMessage", func() { + It("should receive a message from []*FailedMessage", func() { failedMessages, err := q.Enqueue(ctx, messages) Expect(err).ToNot(HaveOccurred()) Expect(failedMessages).To(HaveLen(1)) @@ -123,7 +122,7 @@ var _ = Describe("Queue interface", func() { var errorMsg string BeforeEach(func() { - errorMsg = "internal errror" + errorMsg = "internal error" mockQ.EXPECT().Enqueue(gomock.Any(), gomock.Any()).Return( nil, errors.New(errorMsg), @@ -192,7 +191,7 @@ var _ = Describe("Queue interface", func() { messages, err := q.Dequeue(ctx, depth) Expect(err).ToNot(HaveOccurred()) - _, ok := messages[0].(*receivedMessageImpl) + _, ok := messages[0].(*leasedMessage) Expect(ok).To(BeTrue()) }) @@ -227,4 +226,4 @@ var _ = Describe("Queue interface", func() { }) }) }) -}) \ No newline at end of file +}) diff --git a/api/queues/task.go b/nitric/queues/message.go similarity index 85% rename from api/queues/task.go rename to nitric/queues/message.go index b6f0657..0da38b7 100644 --- a/api/queues/task.go +++ b/nitric/queues/message.go @@ -17,8 +17,8 @@ package queues import ( "context" - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" + "github.com/nitrictech/go-sdk/nitric/errors" + "github.com/nitrictech/go-sdk/nitric/errors/codes" v1 "github.com/nitrictech/nitric/core/pkg/proto/queues/v1" "github.com/nitrictech/protoutils" ) @@ -32,22 +32,22 @@ type ReceivedMessage interface { Complete(context.Context) error } -type receivedMessageImpl struct { +type leasedMessage struct { queueName string queueClient v1.QueuesClient leaseId string message map[string]interface{} } -func (r *receivedMessageImpl) Message() map[string]interface{} { +func (r *leasedMessage) Message() map[string]interface{} { return r.message } -func (r *receivedMessageImpl) Queue() string { +func (r *leasedMessage) Queue() string { return r.queueName } -func (r *receivedMessageImpl) Complete(ctx context.Context) error { +func (r *leasedMessage) Complete(ctx context.Context) error { _, err := r.queueClient.Complete(ctx, &v1.QueueCompleteRequest{ QueueName: r.queueName, LeaseId: r.leaseId, @@ -69,7 +69,7 @@ func messageToWire(message map[string]interface{}) (*v1.QueueMessage, error) { if err != nil { return nil, errors.NewWithCause( codes.Internal, - "messageToWire: failed to serialize payload: %s", + "messageToWire: failed to serialize message: %s", err, ) } diff --git a/api/queues/task_test.go b/nitric/queues/message_test.go similarity index 98% rename from api/queues/task_test.go rename to nitric/queues/message_test.go index cc44d36..5190feb 100644 --- a/api/queues/task_test.go +++ b/nitric/queues/message_test.go @@ -45,7 +45,7 @@ var _ = Describe("ReceivedMessage", func() { message = map[string]interface{}{ "message": "hello", } - receivedMsg = &receivedMessageImpl{ + receivedMsg = &leasedMessage{ queueName: queueName, queueClient: mockQ, leaseId: leaseID, @@ -124,4 +124,4 @@ var _ = Describe("Helper functions", func() { Expect(convertedMessage).To(Equal(message)) }) }) -}) \ No newline at end of file +}) diff --git a/nitric/queue.go b/nitric/queues/queue.go similarity index 68% rename from nitric/queue.go rename to nitric/queues/queue.go index c96ad76..2b8c62a 100644 --- a/nitric/queue.go +++ b/nitric/queues/queue.go @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package nitric +package queues import ( "fmt" - "github.com/nitrictech/go-sdk/api/queues" + "github.com/nitrictech/go-sdk/nitric/workers" v1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" ) @@ -31,23 +31,25 @@ const ( var QueueEverything []QueuePermission = []QueuePermission{QueueEnqueue, QueueDequeue} type Queue interface { - Allow(QueuePermission, ...QueuePermission) (queues.Queue, error) + // Allow requests the given permissions to the queue. + Allow(permission QueuePermission, permissions ...QueuePermission) *QueueClient } type queue struct { name string - manager Manager - registerChan <-chan RegisterResult + manager *workers.Manager + registerChan <-chan workers.RegisterResult } +// NewQueue - Create a new Queue resource func NewQueue(name string) *queue { queue := &queue{ name: name, - manager: defaultManager, - registerChan: make(chan RegisterResult), + manager: workers.GetDefaultManager(), + registerChan: make(chan workers.RegisterResult), } - queue.registerChan = defaultManager.registerResource(&v1.ResourceDeclareRequest{ + queue.registerChan = queue.manager.RegisterResource(&v1.ResourceDeclareRequest{ Id: &v1.ResourceIdentifier{ Type: v1.ResourceType_Queue, Name: name, @@ -60,8 +62,7 @@ func NewQueue(name string) *queue { return queue } -// NewQueue registers this queue as a required resource for the calling function/container. -func (q *queue) Allow(permission QueuePermission, permissions ...QueuePermission) (queues.Queue, error) { +func (q *queue) Allow(permission QueuePermission, permissions ...QueuePermission) *QueueClient { allPerms := append([]QueuePermission{permission}, permissions...) actions := []v1.Action{} @@ -72,26 +73,24 @@ func (q *queue) Allow(permission QueuePermission, permissions ...QueuePermission case QueueEnqueue: actions = append(actions, v1.Action_QueueEnqueue) default: - return nil, fmt.Errorf("QueuePermission %s unknown", perm) + panic(fmt.Sprintf("QueuePermission %s unknown", perm)) } } registerResult := <-q.registerChan if registerResult.Err != nil { - return nil, registerResult.Err + panic(registerResult.Err) } - m, err := q.manager.registerPolicy(registerResult.Identifier, actions...) + err := q.manager.RegisterPolicy(registerResult.Identifier, actions...) if err != nil { - return nil, err + panic(err) } - if m.queues == nil { - m.queues, err = queues.New() - if err != nil { - return nil, err - } + client, err := NewQueueClient(q.name) + if err != nil { + panic(err) } - return m.queues.Queue(q.name), nil + return client } diff --git a/api/queues/queues_suite_test.go b/nitric/queues/queues_suite_test.go similarity index 100% rename from api/queues/queues_suite_test.go rename to nitric/queues/queues_suite_test.go diff --git a/nitric/resource/resource.go b/nitric/resource/resource.go new file mode 100644 index 0000000..0b30e25 --- /dev/null +++ b/nitric/resource/resource.go @@ -0,0 +1,24 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package resources + +type Details struct { + // The identifier of the resource + ID string + // The provider this resource is deployed with (e.g. aws) + Provider string + // The service this resource is deployed on (e.g. ApiGateway) + Service string +} diff --git a/nitric/resources_suite_test.go b/nitric/resources_suite_test.go index e30441f..9d7d6b5 100644 --- a/nitric/resources_suite_test.go +++ b/nitric/resources_suite_test.go @@ -14,14 +14,14 @@ package nitric -// import ( -// "testing" +import ( + "testing" -// . "github.com/onsi/ginkgo" -// . "github.com/onsi/gomega" -// ) + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) -// func TestResources(t *testing.T) { -// RegisterFailHandler(Fail) -// RunSpecs(t, "Resources Suite") -// } +func TestNitric(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Nitric Suite") +} diff --git a/nitric/schedule.go b/nitric/schedule.go deleted file mode 100644 index 6dfd516..0000000 --- a/nitric/schedule.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package nitric - -import ( - "strings" - - "github.com/nitrictech/go-sdk/handler" - "github.com/nitrictech/go-sdk/workers" - schedulespb "github.com/nitrictech/nitric/core/pkg/proto/schedules/v1" -) - -type Schedule interface { - Cron(cron string, middleware ...handler.IntervalMiddleware) - Every(rate string, middleware ...handler.IntervalMiddleware) -} - -type schedule struct { - Schedule - - name string - manager Manager -} - -// NewSchedule provides a new schedule, which can be configured with a rate/cron and a callback to run on the schedule. -func NewSchedule(name string) Schedule { - return &schedule{ - name: name, - manager: defaultManager, - } -} - -// Run middleware at a certain interval defined by the cronExpression. -func (s *schedule) Cron(cron string, middleware ...handler.IntervalMiddleware) { - scheduleCron := &schedulespb.ScheduleCron{ - Expression: cron, - } - - registrationRequest := &schedulespb.RegistrationRequest{ - ScheduleName: s.name, - Cadence: &schedulespb.RegistrationRequest_Cron{ - Cron: scheduleCron, - }, - } - - composeHandler := handler.ComposeIntervalMiddleware(middleware...) - - opts := &workers.IntervalWorkerOpts{ - RegistrationRequest: registrationRequest, - Middleware: composeHandler, - } - - worker := workers.NewIntervalWorker(opts) - s.manager.addWorker("IntervalWorkerCron:"+strings.Join([]string{ - s.name, - cron, - }, "-"), worker) -} - -// Run middleware at a certain interval defined by the rate. The rate is e.g. '7 days'. All rates accept a number and a frequency. Valid frequencies are 'days', 'hours' or 'minutes'. -func (s *schedule) Every(rate string, middleware ...handler.IntervalMiddleware) { - scheduleEvery := &schedulespb.ScheduleEvery{ - Rate: rate, - } - - registrationRequest := &schedulespb.RegistrationRequest{ - ScheduleName: s.name, - Cadence: &schedulespb.RegistrationRequest_Every{ - Every: scheduleEvery, - }, - } - - composeHandler := handler.ComposeIntervalMiddleware(middleware...) - - opts := &workers.IntervalWorkerOpts{ - RegistrationRequest: registrationRequest, - Middleware: composeHandler, - } - - worker := workers.NewIntervalWorker(opts) - s.manager.addWorker("IntervalWorkerEvery:"+strings.Join([]string{ - s.name, - rate, - }, "-"), worker) -} diff --git a/nitric/schedule_test.go b/nitric/schedule_test.go deleted file mode 100644 index f408283..0000000 --- a/nitric/schedule_test.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package nitric - -// import ( -// "github.com/nitrictech/go-sdk/faas" -// . "github.com/onsi/ginkgo" -// . "github.com/onsi/gomega" -// ) - -// var _ = Describe("schedule", func() { -// Context("New", func() { -// m := &manager{ -// workers: map[string]Starter{}, -// builders: map[string]faas.HandlerBuilder{}, -// } -// When("valid args", func() { -// err := m.newSchedule("regular").Every("4 minutes", func(ec *faas.EventContext, eh faas.EventHandler) (*faas.EventContext, error) { -// return eh(ec) -// }) - -// It("should not return an error", func() { -// Expect(err).ShouldNot(HaveOccurred()) -// b := m.builders["regular"] -// Expect(b).ToNot(BeNil()) -// }) -// }) -// When("invalid schedule", func() { -// err := m.newSchedule("invalid").Every("four minutes", func(ec *faas.EventContext, eh faas.EventHandler) (*faas.EventContext, error) { -// return eh(ec) -// }) - -// It("should return an error", func() { -// Expect(err).To(MatchError("invalid rate expression four minutes; strconv.Atoi: parsing \"four\": invalid syntax")) -// b := m.builders["invalid"] -// Expect(b).To(BeNil()) -// }) -// }) -// }) -// Context("rateSplit", func() { -// When("hours", func() { -// It("2 hours", func() { -// r, f, err := rateSplit("2 hours") -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(r).To(Equal(2)) -// Expect(f).To(Equal(faas.Frequency("hours"))) -// }) -// It("1 hours", func() { -// r, f, err := rateSplit("1 hours") -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(r).To(Equal(1)) -// Expect(f).To(Equal(faas.Frequency("hours"))) -// }) -// It("hour", func() { -// r, f, err := rateSplit("hour") -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(r).To(Equal(1)) -// Expect(f).To(Equal(faas.Frequency("hours"))) -// }) -// }) -// When("days", func() { -// It("day", func() { -// r, f, err := rateSplit("day") -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(r).To(Equal(1)) -// Expect(f).To(Equal(faas.Frequency("days"))) -// }) -// It("1 day", func() { -// r, f, err := rateSplit("1 days") -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(r).To(Equal(1)) -// Expect(f).To(Equal(faas.Frequency("days"))) -// }) -// It("89 day", func() { -// r, f, err := rateSplit("89 days") -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(r).To(Equal(89)) -// Expect(f).To(Equal(faas.Frequency("days"))) -// }) -// }) -// When("minutes", func() { -// It("minute", func() { -// r, f, err := rateSplit("minute") -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(r).To(Equal(1)) -// Expect(f).To(Equal(faas.Frequency("minutes"))) -// }) -// It("1 minutes", func() { -// r, f, err := rateSplit("1 minutes") -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(r).To(Equal(1)) -// Expect(f).To(Equal(faas.Frequency("minutes"))) -// }) -// It("89 minutes", func() { -// r, f, err := rateSplit("89 minutes") -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(r).To(Equal(89)) -// Expect(f).To(Equal(faas.Frequency("minutes"))) -// }) -// }) -// }) -// }) diff --git a/nitric/schedules/context.go b/nitric/schedules/context.go new file mode 100644 index 0000000..ae131a5 --- /dev/null +++ b/nitric/schedules/context.go @@ -0,0 +1,51 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package schedules + +import schedulespb "github.com/nitrictech/nitric/core/pkg/proto/schedules/v1" + +type Ctx struct { + id string + Request Request + Response *Response + Extras map[string]interface{} +} + +func (c *Ctx) ToClientMessage() *schedulespb.ClientMessage { + return &schedulespb.ClientMessage{ + Id: c.id, + Content: &schedulespb.ClientMessage_IntervalResponse{ + IntervalResponse: &schedulespb.IntervalResponse{}, + }, + } +} + +func NewCtx(msg *schedulespb.ServerMessage) *Ctx { + return &Ctx{ + id: msg.Id, + Request: &scheduleRequest{ + scheduleName: msg.GetIntervalRequest().ScheduleName, + }, + Response: &Response{ + Success: true, + }, + } +} + +func (c *Ctx) WithError(err error) { + c.Response = &Response{ + Success: false, + } +} diff --git a/nitric/schedules/request.go b/nitric/schedules/request.go new file mode 100644 index 0000000..3a75d65 --- /dev/null +++ b/nitric/schedules/request.go @@ -0,0 +1,27 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package schedules + +type Request interface { + ScheduleName() string +} + +type scheduleRequest struct { + scheduleName string +} + +func (i *scheduleRequest) ScheduleName() string { + return i.scheduleName +} diff --git a/nitric/schedules/response.go b/nitric/schedules/response.go new file mode 100644 index 0000000..05f6e2b --- /dev/null +++ b/nitric/schedules/response.go @@ -0,0 +1,19 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package schedules + +type Response struct { + Success bool +} diff --git a/nitric/schedules/schedule.go b/nitric/schedules/schedule.go new file mode 100644 index 0000000..d0bde6f --- /dev/null +++ b/nitric/schedules/schedule.go @@ -0,0 +1,118 @@ +// Copyright 2021 Nitric Technologies Pty Ltd. +// +// 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. + +package schedules + +import ( + "strings" + + "github.com/nitrictech/go-sdk/internal/handlers" + "github.com/nitrictech/go-sdk/nitric/workers" + schedulespb "github.com/nitrictech/nitric/core/pkg/proto/schedules/v1" +) + +type Schedule interface { + // Run a function at a certain interval defined by the cronExpression. + // Valid function signatures for handler are: + // + // func() + // func() error + // func(*schedules.Ctx) + // func(*schedules.Ctx) error + // Handler[schedules.Ctx] + Cron(cron string, handler interface{}) + + // Run a function at a certain interval defined by the rate. The rate is e.g. '7 days'. All rates accept a number and a frequency. Valid frequencies are 'days', 'hours' or 'minutes'. + // Valid function signatures for handler are: + // + // func() + // func() error + // func(*schedules.Ctx) + // func(*schedules.Ctx) error + // Handler[schedules.Ctx] + Every(rate string, handler interface{}) +} + +type schedule struct { + name string + manager *workers.Manager +} + +var _ Schedule = (*schedule)(nil) + +// NewSchedule - Create a new Schedule resource +func NewSchedule(name string) Schedule { + return &schedule{ + name: name, + manager: workers.GetDefaultManager(), + } +} + +func (s *schedule) Cron(cron string, handler interface{}) { + scheduleCron := &schedulespb.ScheduleCron{ + Expression: cron, + } + + registrationRequest := &schedulespb.RegistrationRequest{ + ScheduleName: s.name, + Cadence: &schedulespb.RegistrationRequest_Cron{ + Cron: scheduleCron, + }, + } + + typedHandler, err := handlers.HandlerFromInterface[Ctx](handler) + if err != nil { + panic(err) + } + + opts := &scheduleWorkerOpts{ + RegistrationRequest: registrationRequest, + Handler: typedHandler, + } + + worker := newScheduleWorker(opts) + s.manager.AddWorker("IntervalWorkerCron:"+strings.Join([]string{ + s.name, + cron, + }, "-"), worker) +} + +func (s *schedule) Every(rate string, handler interface{}) { + scheduleEvery := &schedulespb.ScheduleEvery{ + Rate: rate, + } + + registrationRequest := &schedulespb.RegistrationRequest{ + ScheduleName: s.name, + Cadence: &schedulespb.RegistrationRequest_Every{ + Every: scheduleEvery, + }, + } + + typedHandler, err := handlers.HandlerFromInterface[Ctx](handler) + if err != nil { + panic(err) + } + + opts := &scheduleWorkerOpts{ + RegistrationRequest: registrationRequest, + Handler: typedHandler, + } + + worker := newScheduleWorker(opts) + s.manager.AddWorker("IntervalWorkerEvery:"+strings.Join([]string{ + s.name, + rate, + }, "-"), worker) +} diff --git a/workers/interval.go b/nitric/schedules/schedule_workers.go similarity index 62% rename from workers/interval.go rename to nitric/schedules/schedule_workers.go index 28597c0..d94fa68 100644 --- a/workers/interval.go +++ b/nitric/schedules/schedule_workers.go @@ -12,34 +12,32 @@ // See the License for the specific language governing permissions and // limitations under the License. -package workers +package schedules import ( "context" - "fmt" + errorsstd "errors" "io" - "google.golang.org/grpc" - - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" - "github.com/nitrictech/go-sdk/constants" - "github.com/nitrictech/go-sdk/handler" + grpcx "github.com/nitrictech/go-sdk/internal/grpc" + "github.com/nitrictech/go-sdk/internal/handlers" + "github.com/nitrictech/go-sdk/nitric/errors" + "github.com/nitrictech/go-sdk/nitric/errors/codes" v1 "github.com/nitrictech/nitric/core/pkg/proto/schedules/v1" ) -type IntervalWorker struct { +type scheduleWorker struct { client v1.SchedulesClient registrationRequest *v1.RegistrationRequest - middleware handler.IntervalMiddleware + handler handlers.Handler[Ctx] } -type IntervalWorkerOpts struct { +type scheduleWorkerOpts struct { RegistrationRequest *v1.RegistrationRequest - Middleware handler.IntervalMiddleware + Handler handlers.Handler[Ctx] } // Start implements Worker. -func (i *IntervalWorker) Start(ctx context.Context) error { +func (i *scheduleWorker) Start(ctx context.Context) error { initReq := &v1.ClientMessage{ Content: &v1.ClientMessage_RegistrationRequest{ RegistrationRequest: i.registrationRequest, @@ -57,11 +55,11 @@ func (i *IntervalWorker) Start(ctx context.Context) error { return err } for { - var ctx *handler.IntervalContext + var ctx *Ctx resp, err := stream.Recv() - if err == io.EOF { + if errorsstd.Is(err, io.EOF) { err = stream.CloseSend() if err != nil { return err @@ -69,11 +67,10 @@ func (i *IntervalWorker) Start(ctx context.Context) error { return nil } else if err == nil && resp.GetRegistrationResponse() != nil { - // Interval worker has connected with Nitric server - fmt.Println("IntervalWorker connected with Nitric server") + // There is no need to respond to the registration response } else if err == nil && resp.GetIntervalRequest() != nil { - ctx = handler.NewIntervalContext(resp) - ctx, err = i.middleware(ctx, handler.IntervalDummy) + ctx = NewCtx(resp) + err = i.handler(ctx) if err != nil { ctx.WithError(err) } @@ -88,27 +85,21 @@ func (i *IntervalWorker) Start(ctx context.Context) error { } } -func NewIntervalWorker(opts *IntervalWorkerOpts) *IntervalWorker { - ctx, _ := context.WithTimeout(context.TODO(), constants.NitricDialTimeout()) - - conn, err := grpc.DialContext( - ctx, - constants.NitricAddress(), - constants.DefaultOptions()..., - ) +func newScheduleWorker(opts *scheduleWorkerOpts) *scheduleWorker { + conn, err := grpcx.GetConnection() if err != nil { panic(errors.NewWithCause( codes.Unavailable, - "NewIntervalWorker: Unable to reach StorageListenerClient", + "NewScheduleWorker: Unable to reach SchedulesClient", err, )) } client := v1.NewSchedulesClient(conn) - return &IntervalWorker{ + return &scheduleWorker{ client: client, registrationRequest: opts.RegistrationRequest, - middleware: opts.Middleware, + handler: opts.Handler, } } diff --git a/nitric/secret_test.go b/nitric/secret_test.go deleted file mode 100644 index cb75caf..0000000 --- a/nitric/secret_test.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package nitric - -// import ( -// "context" - -// . "github.com/onsi/ginkgo" -// . "github.com/onsi/gomega" - -// "github.com/golang/mock/gomock" - -// mock_v1 "github.com/nitrictech/go-sdk/mocks" -// "github.com/nitrictech/go-sdk/mocks/mockapi" -// nitricv1 "github.com/nitrictech/nitric/core/pkg/api/nitric/v1" -// ) - -// var _ = Describe("secrets", func() { -// ctrl := gomock.NewController(GinkgoT()) -// Context("New", func() { -// mockConn := mock_v1.NewMockClientConnInterface(ctrl) -// When("valid args", func() { -// mockClient := mock_v1.NewMockResourceServiceClient(ctrl) -// mockSecrets := mockapi.NewMockSecrets(ctrl) - -// m := &manager{ -// workers: map[string]Starter{}, -// conn: mockConn, -// rsc: mockClient, -// secrets: mockSecrets, -// } - -// mockClient.EXPECT().Declare(context.Background(), -// &nitricv1.ResourceDeclareRequest{ -// Resource: &nitricv1.Resource{ -// Type: nitricv1.ResourceType_Secret, -// Name: "gold", -// }, -// Config: &nitricv1.ResourceDeclareRequest_Secret{ -// Secret: &nitricv1.SecretResource{}, -// }, -// }) - -// mockClient.EXPECT().Declare(context.Background(), -// &nitricv1.ResourceDeclareRequest{ -// Resource: &nitricv1.Resource{ -// Type: nitricv1.ResourceType_Policy, -// }, -// Config: &nitricv1.ResourceDeclareRequest_Policy{ -// Policy: &nitricv1.PolicyResource{ -// Principals: []*nitricv1.Resource{{ -// Type: nitricv1.ResourceType_Function, -// }}, -// Actions: []nitricv1.Action{ -// nitricv1.Action_SecretPut, nitricv1.Action_SecretAccess, -// }, -// Resources: []*nitricv1.Resource{{ -// Type: nitricv1.ResourceType_Secret, -// Name: "gold", -// }}, -// }, -// }, -// }) - -// mockSecretRef := mockapi.NewMockSecretRef(ctrl) -// mockSecrets.EXPECT().Secret("gold").Return(mockSecretRef) -// b, err := m.newSecret("gold", SecretPutting, SecretAccessing) - -// It("should not return an error", func() { -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(b).ShouldNot(BeNil()) -// }) -// }) -// }) -// }) diff --git a/nitric/secrets/client.go b/nitric/secrets/client.go new file mode 100644 index 0000000..6c72866 --- /dev/null +++ b/nitric/secrets/client.go @@ -0,0 +1,111 @@ +// Copyright 2021 Nitric Technologies Pty Ltd. +// +// 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. + +package secrets + +import ( + "context" + + grpcx "github.com/nitrictech/go-sdk/internal/grpc" + "github.com/nitrictech/go-sdk/nitric/errors" + "github.com/nitrictech/go-sdk/nitric/errors/codes" + v1 "github.com/nitrictech/nitric/core/pkg/proto/secrets/v1" +) + +type SecretValue []byte + +func (s SecretValue) AsString() string { + return string(s) +} + +type SecretClientIface interface { + // Name - Return the name of this secret + Name() string + // Put - Store a new value in this secret, returning a reference to the new version created + Put(ctx context.Context, value []byte) (string, error) + // Access - Access the latest version of this secret + Access(ctx context.Context) (SecretValue, error) + // AccessVersion - Access a specific version of the secret + AccessVersion(ctx context.Context, version string) (SecretValue, error) +} + +var _ SecretClientIface = (*SecretClient)(nil) + +// SecretClient - Reference to a cloud secret +type SecretClient struct { + name string + secretClient v1.SecretManagerClient +} + +// Name - Return the name of this secret +func (s *SecretClient) Name() string { + return s.name +} + +// Put - Store a new value in this secret, returning a reference to the new version created +func (s *SecretClient) Put(ctx context.Context, value []byte) (string, error) { + resp, err := s.secretClient.Put(ctx, &v1.SecretPutRequest{ + Secret: &v1.Secret{ + Name: s.name, + }, + Value: value, + }) + if err != nil { + return "", errors.FromGrpcError(err) + } + + return resp.GetSecretVersion().Version, nil +} + +const latestVersionId = "latest" + +// Access - Access the latest version of this secret +func (s *SecretClient) Access(ctx context.Context) (SecretValue, error) { + return s.AccessVersion(ctx, latestVersionId) +} + +// AccessVersion - Access a specific version of the secret +func (s *SecretClient) AccessVersion(ctx context.Context, version string) (SecretValue, error) { + r, err := s.secretClient.Access(ctx, &v1.SecretAccessRequest{ + SecretVersion: &v1.SecretVersion{ + Secret: &v1.Secret{ + Name: s.name, + }, + Version: version, + }, + }) + if err != nil { + return nil, errors.FromGrpcError(err) + } + + return SecretValue(r.GetValue()), nil +} + +func NewSecretClient(name string) (*SecretClient, error) { + conn, err := grpcx.GetConnection() + if err != nil { + return nil, errors.NewWithCause( + codes.Unavailable, + "NewSecretClient: unable to reach nitric server", + err, + ) + } + + sClient := v1.NewSecretManagerClient(conn) + + return &SecretClient{ + secretClient: sClient, + name: name, + }, nil +} diff --git a/api/secrets/secret_ref_test.go b/nitric/secrets/client_test.go similarity index 54% rename from api/secrets/secret_ref_test.go rename to nitric/secrets/client_test.go index 24c4373..cf36fc2 100644 --- a/api/secrets/secret_ref_test.go +++ b/nitric/secrets/client_test.go @@ -27,24 +27,21 @@ import ( v1 "github.com/nitrictech/nitric/core/pkg/proto/secrets/v1" ) -var _ = Describe("secretRefImpl", func() { +var _ = Describe("Secret", func() { var ( - ctrl *gomock.Controller - mockSC *mock_v1.MockSecretManagerClient - secrets *secretsImpl - secretsName string - sr SecretRef - ctx context.Context + ctrl *gomock.Controller + mockSC *mock_v1.MockSecretManagerClient + secret *SecretClient + ctx context.Context ) BeforeEach(func() { ctrl = gomock.NewController(GinkgoT()) mockSC = mock_v1.NewMockSecretManagerClient(ctrl) - secrets = &secretsImpl{ + secret = &SecretClient{ + name: "test-secret", secretClient: mockSC, } - secretsName = "test-secrets" - sr = secrets.Secret(secretsName) ctx = context.Background() }) @@ -55,72 +52,19 @@ var _ = Describe("secretRefImpl", func() { Context("Having a valid secretRef", func() { Describe("Name", func() { It("should return the correct secrets name", func() { - Expect(sr.Name()).To(Equal(secretsName)) - }) - }) - - Describe("Version", func() { - versionName := "test-version" - _sr := &secretRefImpl{ - name: secretsName, - secretClient: mockSC, - } - sv := _sr.Version(versionName) - svi, ok := sv.(*secretVersionRefImpl) - - It("should be of type secretVersionRefImpl", func() { - Expect(ok).To(BeTrue()) - }) - - It("should share a secret client references with its parent secret", func() { - Expect(svi.secretClient).To(Equal(_sr.secretClient)) - }) - - It("should have a back reference to it's parent secret", func() { - Expect(svi.secret).To(Equal(_sr)) - }) - - It("should have a the requested version name", func() { - Expect(svi.version).To(Equal(versionName)) - }) - }) - - Describe("Latest", func() { - When("retrieving a the latest secret version reference", func() { - _sr := &secretRefImpl{ - name: secretsName, - secretClient: mockSC, - } - sv := _sr.Latest() - svi, ok := sv.(*secretVersionRefImpl) - - It("should be of type secretVersionRefImpl", func() { - Expect(ok).To(BeTrue()) - }) - - It("should share a secret client references with its parent secret", func() { - Expect(svi.secretClient).To(Equal(_sr.secretClient)) - }) - - It("should have a back reference to it's parent secret", func() { - Expect(svi.secret).To(Equal(_sr)) - }) - - It("should have 'latest' as it's version name", func() { - Expect(svi.version).To(Equal("latest")) - }) + Expect(secret.Name()).To(Equal("test-secret")) }) }) Describe("Put", func() { var ( - _sr *secretRefImpl + _sr *SecretClient secretValue []byte ) BeforeEach(func() { - _sr = &secretRefImpl{ - name: secretsName, + _sr = &SecretClient{ + name: "test-secret", secretClient: mockSC, } secretValue = []byte("ssssshhhh... it's a secret") @@ -158,16 +102,8 @@ var _ = Describe("secretRefImpl", func() { By("not returning an error") Expect(err).ToNot(HaveOccurred()) - svi, ok := sv.(*secretVersionRefImpl) - - By("returning a secretVersionRefImpl") - Expect(ok).To(BeTrue()) - - By("returning the correct secret version") - Expect(svi.version).To(Equal(versionName)) - - By("attaching a reference to the parent secret") - Expect(svi.secret).To(Equal(_sr)) + By("returning a string secret version") + Expect(sv).To(Equal(versionName)) }) }) @@ -190,8 +126,8 @@ var _ = Describe("secretRefImpl", func() { Expect(err).To(HaveOccurred()) Expect(strings.Contains(err.Error(), errorMsg)).To(BeTrue()) - By("returning a nil secret version reference") - Expect(sv).To(BeNil()) + By("returning a blank secret version reference") + Expect(sv).To(BeEmpty()) }) }) }) diff --git a/nitric/secret.go b/nitric/secrets/secret.go similarity index 70% rename from nitric/secret.go rename to nitric/secrets/secret.go index a1c80c5..6c3972e 100644 --- a/nitric/secret.go +++ b/nitric/secrets/secret.go @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package nitric +package secrets import ( "fmt" - "github.com/nitrictech/go-sdk/api/secrets" + "github.com/nitrictech/go-sdk/nitric/workers" v1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" ) @@ -31,22 +31,24 @@ const ( var SecretEverything []SecretPermission = []SecretPermission{SecretAccess, SecretPut} type Secret interface { - Allow(SecretPermission, ...SecretPermission) (secrets.SecretRef, error) + // Allow requests the given permissions to the secret. + Allow(permission SecretPermission, permissions ...SecretPermission) *SecretClient } type secret struct { name string - manager Manager - registerChan <-chan RegisterResult + manager *workers.Manager + registerChan <-chan workers.RegisterResult } +// NewSecret - Create a new Secret resource func NewSecret(name string) *secret { secret := &secret{ name: name, - manager: defaultManager, + manager: workers.GetDefaultManager(), } - secret.registerChan = defaultManager.registerResource(&v1.ResourceDeclareRequest{ + secret.registerChan = secret.manager.RegisterResource(&v1.ResourceDeclareRequest{ Id: &v1.ResourceIdentifier{ Type: v1.ResourceType_Secret, Name: name, @@ -59,7 +61,7 @@ func NewSecret(name string) *secret { return secret } -func (s *secret) Allow(permission SecretPermission, permissions ...SecretPermission) (secrets.SecretRef, error) { +func (s *secret) Allow(permission SecretPermission, permissions ...SecretPermission) *SecretClient { allPerms := append([]SecretPermission{permission}, permissions...) actions := []v1.Action{} @@ -70,26 +72,24 @@ func (s *secret) Allow(permission SecretPermission, permissions ...SecretPermiss case SecretPut: actions = append(actions, v1.Action_SecretPut) default: - return nil, fmt.Errorf("secretPermission %s unknown", perm) + panic(fmt.Sprintf("secretPermission %s unknown", perm)) } } registerResult := <-s.registerChan if registerResult.Err != nil { - return nil, registerResult.Err + panic(registerResult.Err) } - m, err := s.manager.registerPolicy(registerResult.Identifier, actions...) + err := s.manager.RegisterPolicy(registerResult.Identifier, actions...) if err != nil { - return nil, err + panic(err) } - if m.secrets == nil { - m.secrets, err = secrets.New() - if err != nil { - return nil, err - } + client, err := NewSecretClient(s.name) + if err != nil { + panic(err) } - return m.secrets.Secret(s.name), nil + return client } diff --git a/api/secrets/secrets_suite_test.go b/nitric/secrets/secrets_suite_test.go similarity index 100% rename from api/secrets/secrets_suite_test.go rename to nitric/secrets/secrets_suite_test.go diff --git a/nitric/sql/client.go b/nitric/sql/client.go new file mode 100644 index 0000000..4670576 --- /dev/null +++ b/nitric/sql/client.go @@ -0,0 +1,70 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package sql + +import ( + "context" + + grpcx "github.com/nitrictech/go-sdk/internal/grpc" + "github.com/nitrictech/go-sdk/nitric/errors" + "github.com/nitrictech/go-sdk/nitric/errors/codes" + + v1 "github.com/nitrictech/nitric/core/pkg/proto/sql/v1" +) + +type SqlClientIface interface { + // Name - The name of the store + Name() string + // Get a value from the store + ConnectionString(ctx context.Context) (string, error) +} + +type SqlClient struct { + name string + sqlClient v1.SqlClient +} + +func (s *SqlClient) Name() string { + return s.name +} + +func (s *SqlClient) ConnectionString(ctx context.Context) (string, error) { + resp, err := s.sqlClient.ConnectionString(ctx, &v1.SqlConnectionStringRequest{ + DatabaseName: s.name, + }) + if err != nil { + return "", err + } + + return resp.ConnectionString, nil +} + +func NewSqlClient(name string) (*SqlClient, error) { + conn, err := grpcx.GetConnection() + if err != nil { + return nil, errors.NewWithCause( + codes.Unavailable, + "unable to reach nitric server", + err, + ) + } + + client := v1.NewSqlClient(conn) + + return &SqlClient{ + name: name, + sqlClient: client, + }, nil +} diff --git a/nitric/sql/sql.go b/nitric/sql/sql.go new file mode 100644 index 0000000..d8e69aa --- /dev/null +++ b/nitric/sql/sql.go @@ -0,0 +1,64 @@ +// Copyright 2021 Nitric Technologies Pty Ltd. +// +// 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. + +package sql + +import ( + "github.com/nitrictech/go-sdk/nitric/workers" + v1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" +) + +type sqlDatabaseOption func(*v1.SqlDatabaseResource) + +func WithMigrationsPath(path string) sqlDatabaseOption { + return func(r *v1.SqlDatabaseResource) { + r.Migrations = &v1.SqlDatabaseMigrations{ + Migrations: &v1.SqlDatabaseMigrations_MigrationsPath{ + MigrationsPath: path, + }, + } + } +} + +// NewSqlDatabase - Create a new Sql Database resource +func NewSqlDatabase(name string, opts ...sqlDatabaseOption) *SqlClient { + resourceConfig := &v1.ResourceDeclareRequest_SqlDatabase{ + SqlDatabase: &v1.SqlDatabaseResource{}, + } + + for _, opt := range opts { + opt(resourceConfig.SqlDatabase) + } + + registerChan := workers.GetDefaultManager().RegisterResource(&v1.ResourceDeclareRequest{ + Id: &v1.ResourceIdentifier{ + Type: v1.ResourceType_SqlDatabase, + Name: name, + }, + Config: resourceConfig, + }) + + // Make sure that registerChan is read + // Currently sql databases do not have allow methods so there is no reason to block on this + go func() { + <-registerChan + }() + + client, err := NewSqlClient(name) + if err != nil { + panic(err) + } + + return client +} diff --git a/nitric/bucket.go b/nitric/storage/bucket.go similarity index 60% rename from nitric/bucket.go rename to nitric/storage/bucket.go index d67baf1..e0b04d9 100644 --- a/nitric/bucket.go +++ b/nitric/storage/bucket.go @@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package nitric +package storage import ( "fmt" "strings" - "github.com/nitrictech/go-sdk/api/storage" - "github.com/nitrictech/go-sdk/handler" - "github.com/nitrictech/go-sdk/workers" + "github.com/nitrictech/go-sdk/internal/handlers" + "github.com/nitrictech/go-sdk/nitric/workers" v1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" storagepb "github.com/nitrictech/nitric/core/pkg/proto/storage/v1" ) @@ -29,13 +28,23 @@ type BucketPermission string type bucket struct { name string - manager Manager - registerChan <-chan RegisterResult + manager *workers.Manager + registerChan <-chan workers.RegisterResult } type Bucket interface { - Allow(BucketPermission, ...BucketPermission) (storage.Bucket, error) - On(handler.BlobEventType, string, ...handler.BlobEventMiddleware) + // Allow requests the given permissions to the bucket. + Allow(permission BucketPermission, permissions ...BucketPermission) *BucketClient + + // On registers a handler for a specific event type on the bucket. + // Valid function signatures for handler are: + // + // func() + // func() error + // func(*storage.Ctx) + // func(*storage.Ctx) error + // Handler[storage.Ctx] + On(eventType EventType, notificationPrefixFilter string, handler interface{}) } const ( @@ -46,15 +55,14 @@ const ( var BucketEverything []BucketPermission = []BucketPermission{BucketRead, BucketWrite, BucketDelete} -// NewBucket register this bucket as a required resource for the calling function/container and -// register the permissions required by the currently scoped function for this resource. +// NewBucket - Create a new Bucket resource func NewBucket(name string) Bucket { bucket := &bucket{ name: name, - manager: defaultManager, + manager: workers.GetDefaultManager(), } - bucket.registerChan = defaultManager.registerResource(&v1.ResourceDeclareRequest{ + bucket.registerChan = bucket.manager.RegisterResource(&v1.ResourceDeclareRequest{ Id: &v1.ResourceIdentifier{ Type: v1.ResourceType_Bucket, Name: name, @@ -67,7 +75,7 @@ func NewBucket(name string) Bucket { return bucket } -func (b *bucket) Allow(permission BucketPermission, permissions ...BucketPermission) (storage.Bucket, error) { +func (b *bucket) Allow(permission BucketPermission, permissions ...BucketPermission) *BucketClient { allPerms := append([]BucketPermission{permission}, permissions...) actions := []v1.Action{} @@ -80,36 +88,34 @@ func (b *bucket) Allow(permission BucketPermission, permissions ...BucketPermiss case BucketDelete: actions = append(actions, v1.Action_BucketFileDelete) default: - return nil, fmt.Errorf("bucketPermission %s unknown", perm) + panic(fmt.Sprintf("bucketPermission %s unknown", perm)) } } registerResult := <-b.registerChan if registerResult.Err != nil { - return nil, registerResult.Err + panic(registerResult.Err) } - m, err := b.manager.registerPolicy(registerResult.Identifier, actions...) + err := b.manager.RegisterPolicy(registerResult.Identifier, actions...) if err != nil { - return nil, err + panic(err) } - if m.storage == nil { - m.storage, err = storage.New() - if err != nil { - return nil, err - } + client, err := NewBucketClient(b.name) + if err != nil { + panic(err) } - return m.storage.Bucket(b.name), nil + return client } -func (b *bucket) On(notificationType handler.BlobEventType, notificationPrefixFilter string, middleware ...handler.BlobEventMiddleware) { +func (b *bucket) On(eventType EventType, notificationPrefixFilter string, handler interface{}) { var blobEventType storagepb.BlobEventType - switch notificationType { - case handler.WriteNotification: + switch eventType { + case WriteNotification: blobEventType = storagepb.BlobEventType_Created - case handler.DeleteNotification: + case DeleteNotification: blobEventType = storagepb.BlobEventType_Deleted } @@ -119,16 +125,19 @@ func (b *bucket) On(notificationType handler.BlobEventType, notificationPrefixFi KeyPrefixFilter: notificationPrefixFilter, } - composedHandler := handler.ComposeBlobEventMiddleware(middleware...) + typedHandler, err := handlers.HandlerFromInterface[Ctx](handler) + if err != nil { + panic(err) + } - opts := &workers.BlobEventWorkerOpts{ + opts := &bucketEventWorkerOpts{ RegistrationRequest: registrationRequest, - Middleware: composedHandler, + Handler: typedHandler, } - worker := workers.NewBlobEventWorker(opts) + worker := newBucketEventWorker(opts) - b.manager.addWorker("bucketNotification:"+strings.Join([]string{ - b.name, notificationPrefixFilter, string(notificationType), + b.manager.AddWorker("bucketNotification:"+strings.Join([]string{ + b.name, notificationPrefixFilter, string(eventType), }, "-"), worker) } diff --git a/workers/blob_event.go b/nitric/storage/bucket_workers.go similarity index 64% rename from workers/blob_event.go rename to nitric/storage/bucket_workers.go index 5f656ca..6e1ba2e 100644 --- a/workers/blob_event.go +++ b/nitric/storage/bucket_workers.go @@ -12,34 +12,32 @@ // See the License for the specific language governing permissions and // limitations under the License. -package workers +package storage import ( "context" - "fmt" + errorsstd "errors" "io" - "google.golang.org/grpc" - - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" - "github.com/nitrictech/go-sdk/constants" - "github.com/nitrictech/go-sdk/handler" + grpcx "github.com/nitrictech/go-sdk/internal/grpc" + "github.com/nitrictech/go-sdk/internal/handlers" + "github.com/nitrictech/go-sdk/nitric/errors" + "github.com/nitrictech/go-sdk/nitric/errors/codes" v1 "github.com/nitrictech/nitric/core/pkg/proto/storage/v1" ) -type BlobEventWorker struct { +type bucketEventWorker struct { client v1.StorageListenerClient registrationRequest *v1.RegistrationRequest - middleware handler.BlobEventMiddleware + handler handlers.Handler[Ctx] } -type BlobEventWorkerOpts struct { +type bucketEventWorkerOpts struct { RegistrationRequest *v1.RegistrationRequest - Middleware handler.BlobEventMiddleware + Handler handlers.Handler[Ctx] } // Start implements Worker. -func (b *BlobEventWorker) Start(ctx context.Context) error { +func (b *bucketEventWorker) Start(ctx context.Context) error { initReq := &v1.ClientMessage{ Content: &v1.ClientMessage_RegistrationRequest{ RegistrationRequest: b.registrationRequest, @@ -57,11 +55,11 @@ func (b *BlobEventWorker) Start(ctx context.Context) error { return err } for { - var ctx *handler.BlobEventContext + var ctx *Ctx resp, err := stream.Recv() - if err == io.EOF { + if errorsstd.Is(err, io.EOF) { err = stream.CloseSend() if err != nil { return err @@ -69,11 +67,10 @@ func (b *BlobEventWorker) Start(ctx context.Context) error { return nil } else if err == nil && resp.GetRegistrationResponse() != nil { - // Blob Notification has connected with Nitric server - fmt.Println("BlobEventWorker connected with Nitric server") + // There is no need to respond to the registration response } else if err == nil && resp.GetBlobEventRequest() != nil { - ctx = handler.NewBlobEventContext(resp) - ctx, err = b.middleware(ctx, handler.BlobEventDummy) + ctx = NewCtx(resp) + err = b.handler(ctx) if err != nil { ctx.WithError(err) } @@ -88,14 +85,8 @@ func (b *BlobEventWorker) Start(ctx context.Context) error { } } -func NewBlobEventWorker(opts *BlobEventWorkerOpts) *BlobEventWorker { - ctx, _ := context.WithTimeout(context.TODO(), constants.NitricDialTimeout()) - - conn, err := grpc.DialContext( - ctx, - constants.NitricAddress(), - constants.DefaultOptions()..., - ) +func newBucketEventWorker(opts *bucketEventWorkerOpts) *bucketEventWorker { + conn, err := grpcx.GetConnection() if err != nil { panic(errors.NewWithCause( codes.Unavailable, @@ -106,9 +97,9 @@ func NewBlobEventWorker(opts *BlobEventWorkerOpts) *BlobEventWorker { client := v1.NewStorageListenerClient(conn) - return &BlobEventWorker{ + return &bucketEventWorker{ client: client, registrationRequest: opts.RegistrationRequest, - middleware: opts.Middleware, + handler: opts.Handler, } } diff --git a/nitric/storage/client.go b/nitric/storage/client.go new file mode 100644 index 0000000..1a4ab76 --- /dev/null +++ b/nitric/storage/client.go @@ -0,0 +1,191 @@ +// Copyright 2021 Nitric Technologies Pty Ltd. +// +// 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. + +package storage + +import ( + "context" + "time" + + "google.golang.org/protobuf/types/known/durationpb" + + grpcx "github.com/nitrictech/go-sdk/internal/grpc" + "github.com/nitrictech/go-sdk/nitric/errors" + "github.com/nitrictech/go-sdk/nitric/errors/codes" + v1 "github.com/nitrictech/nitric/core/pkg/proto/storage/v1" +) + +// Cloud storage bucket resource for large file storage. +type BucketClientIface interface { + // Name - Get the name of the bucket + Name() string + // ListFiles - List the files in the bucket + ListFiles(ctx context.Context) ([]string, error) + // Read - Read this object + Read(ctx context.Context, key string) ([]byte, error) + // Write - Write this object + Write(ctx context.Context, key string, data []byte) error + // Delete - Delete this object + Delete(ctx context.Context, key string) error + // UploadUrl - Creates a signed Url for uploading this file reference + UploadUrl(ctx context.Context, key string, opts ...PresignUrlOption) (string, error) + // DownloadUrl - Creates a signed Url for downloading this file reference + DownloadUrl(ctx context.Context, key string, opts ...PresignUrlOption) (string, error) +} + +var _ BucketClientIface = (*BucketClient)(nil) + +type BucketClient struct { + storageClient v1.StorageClient + name string +} + +func (o *BucketClient) Read(ctx context.Context, key string) ([]byte, error) { + r, err := o.storageClient.Read(ctx, &v1.StorageReadRequest{ + BucketName: o.name, + Key: key, + }) + if err != nil { + return nil, errors.FromGrpcError(err) + } + + return r.GetBody(), nil +} + +func (o *BucketClient) Write(ctx context.Context, key string, content []byte) error { + if _, err := o.storageClient.Write(ctx, &v1.StorageWriteRequest{ + BucketName: o.name, + Key: key, + Body: content, + }); err != nil { + return errors.FromGrpcError(err) + } + + return nil +} + +func (o *BucketClient) Delete(ctx context.Context, key string) error { + if _, err := o.storageClient.Delete(ctx, &v1.StorageDeleteRequest{ + BucketName: o.name, + Key: key, + }); err != nil { + return errors.FromGrpcError(err) + } + + return nil +} + +func (b *BucketClient) ListFiles(ctx context.Context) ([]string, error) { + resp, err := b.storageClient.ListBlobs(ctx, &v1.StorageListBlobsRequest{ + BucketName: b.name, + }) + if err != nil { + return nil, err + } + + fileRefs := make([]string, 0) + + for _, f := range resp.Blobs { + fileRefs = append(fileRefs, f.Key) + } + + return fileRefs, nil +} + +type Mode int + +const ( + ModeRead Mode = iota + ModeWrite +) + +type presignUrlOptions struct { + mode Mode + expiry time.Duration +} + +type PresignUrlOption func(opts *presignUrlOptions) + +func WithPresignUrlExpiry(expiry time.Duration) PresignUrlOption { + return func(opts *presignUrlOptions) { + opts.expiry = expiry + } +} + +func getPresignUrlOpts(mode Mode, opts ...PresignUrlOption) *presignUrlOptions { + defaultOpts := &presignUrlOptions{ + mode: mode, + expiry: time.Minute * 5, + } + + for _, opt := range opts { + opt(defaultOpts) + } + + return defaultOpts +} + +func (o *BucketClient) UploadUrl(ctx context.Context, key string, opts ...PresignUrlOption) (string, error) { + optsWithDefaults := getPresignUrlOpts(ModeWrite, opts...) + + return o.signUrl(ctx, key, optsWithDefaults) +} + +func (o *BucketClient) DownloadUrl(ctx context.Context, key string, opts ...PresignUrlOption) (string, error) { + optsWithDefaults := getPresignUrlOpts(ModeRead, opts...) + + return o.signUrl(ctx, key, optsWithDefaults) +} + +func (o *BucketClient) signUrl(ctx context.Context, key string, opts *presignUrlOptions) (string, error) { + op := v1.StoragePreSignUrlRequest_READ + + if opts.mode == ModeWrite { + op = v1.StoragePreSignUrlRequest_WRITE + } + + r, err := o.storageClient.PreSignUrl(ctx, &v1.StoragePreSignUrlRequest{ + BucketName: o.name, + Key: key, + Operation: op, + Expiry: durationpb.New(opts.expiry), + }) + if err != nil { + return "", errors.FromGrpcError(err) + } + + return r.Url, nil +} + +func (b *BucketClient) Name() string { + return b.name +} + +func NewBucketClient(name string) (*BucketClient, error) { + conn, err := grpcx.GetConnection() + if err != nil { + return nil, errors.NewWithCause( + codes.Unavailable, + "NewBucketClient: unable to reach nitric server", + err, + ) + } + + storageClient := v1.NewStorageClient(conn) + + return &BucketClient{ + name: name, + storageClient: storageClient, + }, nil +} diff --git a/api/storage/bucket_test.go b/nitric/storage/client_test.go similarity index 70% rename from api/storage/bucket_test.go rename to nitric/storage/client_test.go index 0cf5bab..c154334 100644 --- a/api/storage/bucket_test.go +++ b/nitric/storage/client_test.go @@ -31,9 +31,8 @@ var _ = Describe("Bucket", func() { var ( ctrl *gomock.Controller mockStorage *mock_v1.MockStorageClient - bucket *bucketImpl + bucket *BucketClient bucketName string - fileName string ctx context.Context ) @@ -42,9 +41,8 @@ var _ = Describe("Bucket", func() { mockStorage = mock_v1.NewMockStorageClient(ctrl) bucketName = "test-bucket" - fileName = "test-file.txt" - bucket = &bucketImpl{ + bucket = &BucketClient{ name: bucketName, storageClient: mockStorage, } @@ -56,37 +54,8 @@ var _ = Describe("Bucket", func() { ctrl.Finish() }) - Describe("File()", func() { - When("creating a new File reference", func() { - var ( - file File - fileI *fileImpl - ok bool - ) - - BeforeEach(func() { - file = bucket.File(fileName) - fileI, ok = file.(*fileImpl) - }) - - It("it should succesfully return File Instance", func() { - By("returning an fileImpl instance") - Expect(ok).To(BeTrue()) - - By("having the provided file name") - Expect(fileI.key).To(Equal(fileName)) - - By("sharing the bucket name") - Expect(fileI.bucket).To(Equal(bucketName)) - - By("sharing the Bucket's gRPC client") - Expect(fileI.storageClient).To(Equal(mockStorage)) - }) - }) - }) - - Describe("Files()", func() { - When("the gRPC opreation of ListBlobs fails", func() { + Describe("ListFiles()", func() { + When("the gRPC operation of ListBlobs fails", func() { var errorMsg string BeforeEach(func() { @@ -100,7 +69,7 @@ var _ = Describe("Bucket", func() { It("should return an error", func() { By("calling Files() on the bucket reference") - files, err := bucket.Files(ctx) + files, err := bucket.ListFiles(ctx) By("receiving an error with same error message") Expect(err).Should(HaveOccurred()) @@ -111,21 +80,19 @@ var _ = Describe("Bucket", func() { }) }) - When("the gRPC opreation of ListBlobs succeeds", func() { - var files []File + When("the gRPC operation of ListBlobs succeeds", func() { + var files []string BeforeEach(func() { - files = []File{ - bucket.File("file-1.txt"), - bucket.File("file-2.txt"), + files = []string{ + "file-1.txt", + "file-2.txt", } blobs := make([]*v1.Blob, 0, len(files)) for _, file := range files { - fileI, ok := file.(*fileImpl) - Expect(ok).To(BeTrue()) blobs = append(blobs, &v1.Blob{ - Key: fileI.key, + Key: file, }) } @@ -139,7 +106,7 @@ var _ = Describe("Bucket", func() { It("should list the files in the bucket", func() { By("bucket.Files() being called") - _files, err := bucket.Files(ctx) + _files, err := bucket.ListFiles(ctx) By("not returning an error") Expect(err).ToNot(HaveOccurred()) diff --git a/nitric/storage/context.go b/nitric/storage/context.go new file mode 100644 index 0000000..ffc3127 --- /dev/null +++ b/nitric/storage/context.go @@ -0,0 +1,61 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package storage + +import storagepb "github.com/nitrictech/nitric/core/pkg/proto/storage/v1" + +type Ctx struct { + id string + Request Request + Response *Response + Extras map[string]interface{} +} + +func (c *Ctx) ToClientMessage() *storagepb.ClientMessage { + return &storagepb.ClientMessage{ + Id: c.id, + Content: &storagepb.ClientMessage_BlobEventResponse{ + BlobEventResponse: &storagepb.BlobEventResponse{ + Success: c.Response.Success, + }, + }, + } +} + +func NewCtx(msg *storagepb.ServerMessage) *Ctx { + req := msg.GetBlobEventRequest() + + return &Ctx{ + id: msg.Id, + Request: &requestImpl{ + key: req.GetBlobEvent().Key, + }, + Response: &Response{ + Success: true, + }, + } +} + +func (c *Ctx) WithError(err error) { + c.Response = &Response{ + Success: false, + } +} + +// type FileCtx struct { +// Request FileRequest +// Response *FileResponse +// Extras map[string]interface{} +// } diff --git a/nitric/storage/request.go b/nitric/storage/request.go new file mode 100644 index 0000000..f987e2c --- /dev/null +++ b/nitric/storage/request.go @@ -0,0 +1,63 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package storage + +type EventType string + +var EventTypes = []EventType{WriteNotification, DeleteNotification} + +const ( + WriteNotification EventType = "write" + DeleteNotification EventType = "delete" +) + +type Request interface { + Key() string + NotificationType() EventType +} + +type requestImpl struct { + key string + notificationType EventType +} + +func (b *requestImpl) Key() string { + return b.key +} + +func (b *requestImpl) NotificationType() EventType { + return b.notificationType +} + +// File Event + +// XXX: File requests currently not implemented +// type FileRequest interface { +// Bucket() *Bucket +// NotificationType() EventType +// } + +// type fileRequestImpl struct { +// bucket Bucket +// notificationType EventType +// } + +// func (f *fileRequestImpl) Bucket() Bucket { +// return f.bucket +// } + +// func (f *fileRequestImpl) NotificationType() EventType { +// return f.notificationType +// } diff --git a/nitric/storage/response.go b/nitric/storage/response.go new file mode 100644 index 0000000..5ccbab3 --- /dev/null +++ b/nitric/storage/response.go @@ -0,0 +1,23 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package storage + +type Response struct { + Success bool +} + +type FileResponse struct { + Success bool +} diff --git a/api/storage/storage_suite_test.go b/nitric/storage/storage_suite_test.go similarity index 100% rename from api/storage/storage_suite_test.go rename to nitric/storage/storage_suite_test.go diff --git a/nitric/topic_test.go b/nitric/topic_test.go deleted file mode 100644 index 25644a8..0000000 --- a/nitric/topic_test.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2021 Nitric Technologies Pty Ltd. -// -// 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. - -package nitric - -// import ( -// "context" - -// . "github.com/onsi/ginkgo" -// . "github.com/onsi/gomega" - -// "github.com/golang/mock/gomock" - -// mock_v1 "github.com/nitrictech/go-sdk/mocks" -// "github.com/nitrictech/go-sdk/mocks/mockapi" -// nitricv1 "github.com/nitrictech/nitric/core/pkg/api/nitric/v1" -// ) - -// var _ = Describe("topics", func() { -// ctrl := gomock.NewController(GinkgoT()) -// Context("New", func() { -// mockConn := mock_v1.NewMockClientConnInterface(ctrl) -// When("valid args", func() { -// mockClient := mock_v1.NewMockResourceServiceClient(ctrl) -// mockEvents := mockapi.NewMockEvents(ctrl) - -// m := &manager{ -// workers: map[string]Starter{}, -// conn: mockConn, -// rsc: mockClient, -// evts: mockEvents, -// } - -// mockClient.EXPECT().Declare(context.Background(), -// &nitricv1.ResourceDeclareRequest{ -// Resource: &nitricv1.Resource{ -// Type: nitricv1.ResourceType_Topic, -// Name: "news", -// }, -// Config: &nitricv1.ResourceDeclareRequest_Topic{ -// Topic: &nitricv1.TopicResource{}, -// }, -// }) - -// mockClient.EXPECT().Declare(context.Background(), -// &nitricv1.ResourceDeclareRequest{ -// Resource: &nitricv1.Resource{ -// Type: nitricv1.ResourceType_Policy, -// }, -// Config: &nitricv1.ResourceDeclareRequest_Policy{ -// Policy: &nitricv1.PolicyResource{ -// Principals: []*nitricv1.Resource{{ -// Type: nitricv1.ResourceType_Function, -// }}, -// Actions: []nitricv1.Action{}, -// Resources: []*nitricv1.Resource{{ -// Type: nitricv1.ResourceType_Topic, -// Name: "news", -// }}, -// }, -// }, -// }) - -// mockTopic := mockapi.NewMockTopic(ctrl) -// mockEvents.EXPECT().Topic("news").Return(mockTopic) -// b, err := m.newTopic("news") - -// It("should not return an error", func() { -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(b).ShouldNot(BeNil()) -// }) -// }) -// }) -// }) diff --git a/api/topics/topic.go b/nitric/topics/client.go similarity index 65% rename from api/topics/topic.go rename to nitric/topics/client.go index 78257ff..629df92 100644 --- a/api/topics/topic.go +++ b/nitric/topics/client.go @@ -20,29 +20,30 @@ import ( "google.golang.org/protobuf/types/known/durationpb" - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" + grpcx "github.com/nitrictech/go-sdk/internal/grpc" + "github.com/nitrictech/go-sdk/nitric/errors" + "github.com/nitrictech/go-sdk/nitric/errors/codes" v1 "github.com/nitrictech/nitric/core/pkg/proto/topics/v1" "github.com/nitrictech/protoutils" ) -type PublishOption = func(*v1.TopicPublishRequest) +type PublishOption func(*v1.TopicPublishRequest) -// Topic for pub/sub async messaging. -type Topic interface { +// TopicClientIface for pub/sub async messaging. +type TopicClientIface interface { // Name returns the Topic name. Name() string // Publish will publish the provided events on the topic. - Publish(context.Context, map[string]interface{}, ...PublishOption) error + Publish(ctx context.Context, message map[string]interface{}, options ...PublishOption) error } -type topicImpl struct { +type TopicClient struct { name string topicClient v1.TopicsClient } -func (s *topicImpl) Name() string { +func (s *TopicClient) Name() string { return s.name } @@ -53,8 +54,7 @@ func WithDelay(duration time.Duration) func(*v1.TopicPublishRequest) { } } -func (s *topicImpl) Publish(ctx context.Context, message map[string]interface{}, opts ...PublishOption) error { - // Convert payload to Protobuf Struct +func (s *TopicClient) Publish(ctx context.Context, message map[string]interface{}, opts ...PublishOption) error { payloadStruct, err := protoutils.NewStruct(message) if err != nil { return errors.NewWithCause(codes.InvalidArgument, "Topic.Publish", err) @@ -81,3 +81,21 @@ func (s *topicImpl) Publish(ctx context.Context, message map[string]interface{}, return nil } + +func NewTopicClient(name string) (*TopicClient, error) { + conn, err := grpcx.GetConnection() + if err != nil { + return nil, errors.NewWithCause( + codes.Unavailable, + "NewTopicClient: unable to reach nitric server", + err, + ) + } + + topicClient := v1.NewTopicsClient(conn) + + return &TopicClient{ + name: name, + topicClient: topicClient, + }, nil +} diff --git a/api/topics/topic_test.go b/nitric/topics/client_test.go similarity index 97% rename from api/topics/topic_test.go rename to nitric/topics/client_test.go index e02a0d4..9331d9d 100644 --- a/api/topics/topic_test.go +++ b/nitric/topics/client_test.go @@ -28,11 +28,11 @@ import ( "github.com/nitrictech/protoutils" ) -var _ = Describe("File", func() { +var _ = Describe("Topic", func() { var ( ctrl *gomock.Controller mockTopic *mock_v1.MockTopicsClient - t Topic + t *TopicClient topicName string ctx context.Context ) @@ -42,7 +42,7 @@ var _ = Describe("File", func() { mockTopic = mock_v1.NewMockTopicsClient(ctrl) topicName = "test-topic" - t = &topicImpl{ + t = &TopicClient{ name: topicName, topicClient: mockTopic, } diff --git a/nitric/topics/context.go b/nitric/topics/context.go new file mode 100644 index 0000000..bb2e247 --- /dev/null +++ b/nitric/topics/context.go @@ -0,0 +1,54 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package topics + +import topicspb "github.com/nitrictech/nitric/core/pkg/proto/topics/v1" + +type Ctx struct { + id string + Request Request + Response *Response + Extras map[string]interface{} +} + +func (c *Ctx) ToClientMessage() *topicspb.ClientMessage { + return &topicspb.ClientMessage{ + Id: c.id, + Content: &topicspb.ClientMessage_MessageResponse{ + MessageResponse: &topicspb.MessageResponse{ + Success: true, + }, + }, + } +} + +func NewCtx(msg *topicspb.ServerMessage) *Ctx { + return &Ctx{ + id: msg.Id, + Request: &requestImpl{ + topicName: msg.GetMessageRequest().TopicName, + message: msg.GetMessageRequest().Message.GetStructPayload().AsMap(), + }, + Response: &Response{ + Success: true, + }, + } +} + +func (c *Ctx) WithError(err error) { + c.Response = &Response{ + Success: false, + } +} diff --git a/nitric/topics/request.go b/nitric/topics/request.go new file mode 100644 index 0000000..9d147cb --- /dev/null +++ b/nitric/topics/request.go @@ -0,0 +1,33 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package topics + +type Request interface { + TopicName() string + Message() map[string]interface{} +} + +type requestImpl struct { + topicName string + message map[string]interface{} +} + +func (m *requestImpl) TopicName() string { + return m.topicName +} + +func (m *requestImpl) Message() map[string]interface{} { + return m.message +} diff --git a/workers/file_event.go b/nitric/topics/response.go similarity index 91% rename from workers/file_event.go rename to nitric/topics/response.go index 2b54975..f9ecdac 100644 --- a/workers/file_event.go +++ b/nitric/topics/response.go @@ -12,4 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -package workers +package topics + +type Response struct { + Success bool +} diff --git a/nitric/topic.go b/nitric/topics/topic.go similarity index 58% rename from nitric/topic.go rename to nitric/topics/topic.go index 0bd9431..1df2937 100644 --- a/nitric/topic.go +++ b/nitric/topics/topic.go @@ -12,15 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package nitric +package topics import ( "fmt" - "github.com/nitrictech/go-sdk/api/topics" - "github.com/nitrictech/go-sdk/handler" - "github.com/nitrictech/go-sdk/workers" - + "github.com/nitrictech/go-sdk/internal/handlers" + "github.com/nitrictech/go-sdk/nitric/workers" v1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" topicspb "github.com/nitrictech/nitric/core/pkg/proto/topics/v1" ) @@ -29,41 +27,39 @@ import ( type TopicPermission string const ( - // TopicPublishing is required to call Publish on a topic. + // TopicPublish is required to call Publish on a topic. TopicPublish TopicPermission = "publish" ) -type Topic interface { - topics.Topic -} - type SubscribableTopic interface { - Allow(TopicPermission, ...TopicPermission) (Topic, error) + // Allow requests the given permissions to the topic. + Allow(permission TopicPermission, permissions ...TopicPermission) *TopicClient // Subscribe will register and start a subscription handler that will be called for all events from this topic. - Subscribe(...handler.MessageMiddleware) -} - -type topic struct { - topics.Topic - - manager Manager + // Valid function signatures for handler are: + // + // func() + // func() error + // func(*topics.Ctx) + // func(*topics.Ctx) error + // Handler[topics.Ctx] + Subscribe(handler interface{}) } type subscribableTopic struct { name string - manager Manager - registerChan <-chan RegisterResult + manager *workers.Manager + registerChan <-chan workers.RegisterResult } -// NewTopic creates a new Topic with the give permissions. +// NewTopic creates a new Topic with the give name. func NewTopic(name string) SubscribableTopic { topic := &subscribableTopic{ name: name, - manager: defaultManager, + manager: workers.GetDefaultManager(), } - topic.registerChan = defaultManager.registerResource(&v1.ResourceDeclareRequest{ + topic.registerChan = topic.manager.RegisterResource(&v1.ResourceDeclareRequest{ Id: &v1.ResourceIdentifier{ Type: v1.ResourceType_Topic, Name: name, @@ -76,7 +72,7 @@ func NewTopic(name string) SubscribableTopic { return topic } -func (t *subscribableTopic) Allow(permission TopicPermission, permissions ...TopicPermission) (Topic, error) { +func (t *subscribableTopic) Allow(permission TopicPermission, permissions ...TopicPermission) *TopicClient { allPerms := append([]TopicPermission{permission}, permissions...) actions := []v1.Action{} @@ -85,45 +81,43 @@ func (t *subscribableTopic) Allow(permission TopicPermission, permissions ...Top case TopicPublish: actions = append(actions, v1.Action_TopicPublish) default: - return nil, fmt.Errorf("TopicPermission %s unknown", perm) + panic(fmt.Sprintf("TopicPermission %s unknown", perm)) } } registerResult := <-t.registerChan if registerResult.Err != nil { - return nil, registerResult.Err + panic(registerResult.Err) } - m, err := t.manager.registerPolicy(registerResult.Identifier, actions...) + err := t.manager.RegisterPolicy(registerResult.Identifier, actions...) if err != nil { - return nil, err + panic(err) } - if m.topics == nil { - evts, err := topics.New() - if err != nil { - return nil, err - } - m.topics = evts + client, err := NewTopicClient(t.name) + if err != nil { + panic(err) } - return &topic{ - Topic: m.topics.Topic(t.name), - manager: m, - }, nil + return client } -func (t *subscribableTopic) Subscribe(middleware ...handler.MessageMiddleware) { +func (t *subscribableTopic) Subscribe(handler interface{}) { registrationRequest := &topicspb.RegistrationRequest{ TopicName: t.name, } - composeHandler := handler.ComposeMessageMiddleware(middleware...) - opts := &workers.SubscriptionWorkerOpts{ + typedHandler, err := handlers.HandlerFromInterface[Ctx](handler) + if err != nil { + panic(err) + } + + opts := &subscriptionWorkerOpts{ RegistrationRequest: registrationRequest, - Middleware: composeHandler, + Handler: typedHandler, } - worker := workers.NewSubscriptionWorker(opts) - t.manager.addWorker("SubscriptionWorker:"+t.name, worker) + worker := newSubscriptionWorker(opts) + t.manager.AddWorker("SubscriptionWorker:"+t.name, worker) } diff --git a/workers/subscription.go b/nitric/topics/topic_workers.go similarity index 62% rename from workers/subscription.go rename to nitric/topics/topic_workers.go index 8ba2c94..7d6b7a1 100644 --- a/workers/subscription.go +++ b/nitric/topics/topic_workers.go @@ -12,34 +12,33 @@ // See the License for the specific language governing permissions and // limitations under the License. -package workers +package topics import ( "context" - "fmt" "io" - "google.golang.org/grpc" + errorsstd "errors" - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" - "github.com/nitrictech/go-sdk/constants" - "github.com/nitrictech/go-sdk/handler" + grpcx "github.com/nitrictech/go-sdk/internal/grpc" + "github.com/nitrictech/go-sdk/internal/handlers" + "github.com/nitrictech/go-sdk/nitric/errors" + "github.com/nitrictech/go-sdk/nitric/errors/codes" v1 "github.com/nitrictech/nitric/core/pkg/proto/topics/v1" ) -type SubscriptionWorker struct { +type subscriptionWorker struct { client v1.SubscriberClient registrationRequest *v1.RegistrationRequest - middleware handler.MessageMiddleware + handler handlers.Handler[Ctx] } -type SubscriptionWorkerOpts struct { +type subscriptionWorkerOpts struct { RegistrationRequest *v1.RegistrationRequest - Middleware handler.MessageMiddleware + Handler handlers.Handler[Ctx] } // Start implements Worker. -func (s *SubscriptionWorker) Start(ctx context.Context) error { +func (s *subscriptionWorker) Start(ctx context.Context) error { initReq := &v1.ClientMessage{ Content: &v1.ClientMessage_RegistrationRequest{ RegistrationRequest: s.registrationRequest, @@ -57,11 +56,11 @@ func (s *SubscriptionWorker) Start(ctx context.Context) error { return err } for { - var ctx *handler.MessageContext + var ctx *Ctx resp, err := stream.Recv() - if err == io.EOF { + if errorsstd.Is(err, io.EOF) { err = stream.CloseSend() if err != nil { return err @@ -69,11 +68,10 @@ func (s *SubscriptionWorker) Start(ctx context.Context) error { return nil } else if err == nil && resp.GetRegistrationResponse() != nil { - // Subscription worker has connected with Nitric server - fmt.Println("SubscriptionWorker connected with Nitric server") + // There is no need to respond to the registration response } else if err == nil && resp.GetMessageRequest() != nil { - ctx = handler.NewMessageContext(resp) - ctx, err = s.middleware(ctx, handler.MessageDummy) + ctx = NewCtx(resp) + err = s.handler(ctx) if err != nil { ctx.WithError(err) } @@ -88,27 +86,21 @@ func (s *SubscriptionWorker) Start(ctx context.Context) error { } } -func NewSubscriptionWorker(opts *SubscriptionWorkerOpts) *SubscriptionWorker { - ctx, _ := context.WithTimeout(context.TODO(), constants.NitricDialTimeout()) - - conn, err := grpc.DialContext( - ctx, - constants.NitricAddress(), - constants.DefaultOptions()..., - ) +func newSubscriptionWorker(opts *subscriptionWorkerOpts) *subscriptionWorker { + conn, err := grpcx.GetConnection() if err != nil { panic(errors.NewWithCause( codes.Unavailable, - "NewSubscriptionWorker: Unable to reach StorageListenerClient", + "NewSubscriptionWorker: Unable to reach SubscriberClient", err, )) } client := v1.NewSubscriberClient(conn) - return &SubscriptionWorker{ + return &subscriptionWorker{ client: client, registrationRequest: opts.RegistrationRequest, - middleware: opts.Middleware, + handler: opts.Handler, } } diff --git a/api/topics/topics_suite_test.go b/nitric/topics/topics_suite_test.go similarity index 100% rename from api/topics/topics_suite_test.go rename to nitric/topics/topics_suite_test.go diff --git a/nitric/websockets/context.go b/nitric/websockets/context.go new file mode 100644 index 0000000..06aee98 --- /dev/null +++ b/nitric/websockets/context.go @@ -0,0 +1,87 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package websockets + +import websocketspb "github.com/nitrictech/nitric/core/pkg/proto/websockets/v1" + +type Ctx struct { + id string + Request Request + Response *Response + Extras map[string]interface{} +} + +func (c *Ctx) ToClientMessage() *websocketspb.ClientMessage { + return &websocketspb.ClientMessage{ + Id: c.id, + Content: &websocketspb.ClientMessage_WebsocketEventResponse{ + WebsocketEventResponse: &websocketspb.WebsocketEventResponse{ + WebsocketResponse: &websocketspb.WebsocketEventResponse_ConnectionResponse{ + ConnectionResponse: &websocketspb.WebsocketConnectionResponse{ + Reject: c.Response.Reject, + }, + }, + }, + }, + } +} + +func NewCtx(msg *websocketspb.ServerMessage) *Ctx { + req := msg.GetWebsocketEventRequest() + + var eventType EventType + switch req.WebsocketEvent.(type) { + case *websocketspb.WebsocketEventRequest_Disconnection: + eventType = EventType_Disconnect + case *websocketspb.WebsocketEventRequest_Message: + eventType = EventType_Message + default: + eventType = EventType_Connect + } + + queryParams := make(map[string]*websocketspb.QueryValue) + if eventType == EventType_Connect { + for key, value := range req.GetConnection().GetQueryParams() { + queryParams[key] = &websocketspb.QueryValue{ + Value: value.Value, + } + } + } + + var _message string = "" + if req.GetMessage() != nil { + _message = string(req.GetMessage().Body) + } + + return &Ctx{ + id: msg.Id, + Request: &requestImpl{ + socketName: req.SocketName, + eventType: eventType, + connectionId: req.ConnectionId, + queryParams: queryParams, + message: _message, + }, + Response: &Response{ + Reject: false, + }, + } +} + +func (c *Ctx) WithError(err error) { + c.Response = &Response{ + Reject: true, + } +} diff --git a/nitric/websockets/request.go b/nitric/websockets/request.go new file mode 100644 index 0000000..fa4dc55 --- /dev/null +++ b/nitric/websockets/request.go @@ -0,0 +1,71 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package websockets + +import ( + websocketspb "github.com/nitrictech/nitric/core/pkg/proto/websockets/v1" +) + +type EventType string + +var EventTypes = []EventType{EventType_Connect, EventType_Disconnect, EventType_Message} + +const ( + EventType_Connect EventType = "connect" + EventType_Disconnect EventType = "disconnect" + EventType_Message EventType = "message" +) + +type Request interface { + SocketName() string + EventType() EventType + ConnectionID() string + QueryParams() map[string][]string + Message() string +} + +type requestImpl struct { + socketName string + eventType EventType + connectionId string + queryParams map[string]*websocketspb.QueryValue + message string +} + +func (w *requestImpl) SocketName() string { + return w.socketName +} + +func (w *requestImpl) EventType() EventType { + return w.eventType +} + +func (w *requestImpl) ConnectionID() string { + return w.connectionId +} + +func (w *requestImpl) QueryParams() map[string][]string { + queryParams := map[string][]string{} + + for k, v := range w.queryParams { + queryParams[k] = v.Value + } + + return queryParams +} + +func (w *requestImpl) Message() string { + return w.message +} diff --git a/nitric/websockets/response.go b/nitric/websockets/response.go new file mode 100644 index 0000000..1cc3f86 --- /dev/null +++ b/nitric/websockets/response.go @@ -0,0 +1,19 @@ +// Copyright 2023 Nitric Technologies Pty Ltd. +// +// 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. + +package websockets + +type Response struct { + Reject bool +} diff --git a/nitric/websocket.go b/nitric/websockets/websocket.go similarity index 61% rename from nitric/websocket.go rename to nitric/websockets/websocket.go index 944ae96..4c462fa 100644 --- a/nitric/websocket.go +++ b/nitric/websockets/websocket.go @@ -12,22 +12,35 @@ // See the License for the specific language governing permissions and // limitations under the License. -package nitric +package websockets import ( "context" "strings" - "github.com/nitrictech/go-sdk/handler" - "github.com/nitrictech/go-sdk/workers" + grpcx "github.com/nitrictech/go-sdk/internal/grpc" + "github.com/nitrictech/go-sdk/internal/handlers" + "github.com/nitrictech/go-sdk/nitric/workers" resourcesv1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" websocketsv1 "github.com/nitrictech/nitric/core/pkg/proto/websockets/v1" ) +// Websocket - Nitric Websocket API Resource type Websocket interface { + // Name - Get the name of the Websocket API Name() string - On(eventType handler.WebsocketEventType, mwares ...handler.WebsocketMiddleware) + // On registers a handler for a specific event type on the websocket + // Valid function signatures for handler are: + // + // func() + // func() error + // func(*websocket.Ctx) + // func(*websocket.Ctx) error + // Handler[websocket.Ctx] + On(eventType EventType, handler interface{}) + // Send a message to a specific connection Send(ctx context.Context, connectionId string, message []byte) error + // Close a specific connection Close(ctx context.Context, connectionId string) error } @@ -35,49 +48,55 @@ type websocket struct { Websocket name string - manager Manager + manager *workers.Manager client websocketsv1.WebsocketClient } -// NewCollection register this collection as a required resource for the calling function/container. -func NewWebsocket(name string) (Websocket, error) { - registerResult := <-defaultManager.registerResource(&resourcesv1.ResourceDeclareRequest{ +// NewWebsocket - Create a new Websocket API resource +func NewWebsocket(name string) Websocket { + manager := workers.GetDefaultManager() + + registerResult := <-manager.RegisterResource(&resourcesv1.ResourceDeclareRequest{ Id: &resourcesv1.ResourceIdentifier{ Type: resourcesv1.ResourceType_Websocket, Name: name, }, }) if registerResult.Err != nil { - return nil, registerResult.Err + panic(registerResult.Err) } actions := []resourcesv1.Action{resourcesv1.Action_WebsocketManage} - m, err := defaultManager.registerPolicy(registerResult.Identifier, actions...) + err := manager.RegisterPolicy(registerResult.Identifier, actions...) + if err != nil { + panic(err) + } + + conn, err := grpcx.GetConnection() if err != nil { - return nil, err + panic(err) } - wClient := websocketsv1.NewWebsocketClient(m.conn) + wClient := websocketsv1.NewWebsocketClient(conn) return &websocket{ - manager: defaultManager, + manager: manager, client: wClient, name: name, - }, nil + } } func (w *websocket) Name() string { return w.name } -func (w *websocket) On(eventType handler.WebsocketEventType, middleware ...handler.WebsocketMiddleware) { - // mapping handler.WebsocketEventType to protobuf requirement i.e websocketsv1.WebsocketEventType +func (w *websocket) On(eventType EventType, handler interface{}) { var _eventType websocketsv1.WebsocketEventType switch eventType { - case handler.WebsocketDisconnect: + case EventType_Disconnect: _eventType = websocketsv1.WebsocketEventType_Disconnect - case handler.WebsocketMessage: + case EventType_Message: _eventType = websocketsv1.WebsocketEventType_Message default: _eventType = websocketsv1.WebsocketEventType_Connect @@ -87,15 +106,19 @@ func (w *websocket) On(eventType handler.WebsocketEventType, middleware ...handl SocketName: w.name, EventType: _eventType, } - composeHandler := handler.ComposeWebsocketMiddleware(middleware...) - opts := &workers.WebsocketWorkerOpts{ + typedHandler, err := handlers.HandlerFromInterface[Ctx](handler) + if err != nil { + panic(err) + } + + opts := &websocketWorkerOpts{ RegistrationRequest: registrationRequest, - Middleware: composeHandler, + Handler: typedHandler, } - worker := workers.NewWebsocketWorker(opts) - w.manager.addWorker("WebsocketWorker:"+strings.Join([]string{ + worker := newWebsocketWorker(opts) + w.manager.AddWorker("WebsocketWorker:"+strings.Join([]string{ w.name, string(eventType), }, "-"), worker) diff --git a/workers/websocket.go b/nitric/websockets/websocket_workers.go similarity index 62% rename from workers/websocket.go rename to nitric/websockets/websocket_workers.go index ec16e67..e0aafb9 100644 --- a/workers/websocket.go +++ b/nitric/websockets/websocket_workers.go @@ -12,34 +12,32 @@ // See the License for the specific language governing permissions and // limitations under the License. -package workers +package websockets import ( "context" - "fmt" + errorsstd "errors" "io" - "google.golang.org/grpc" - - "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/errors/codes" - "github.com/nitrictech/go-sdk/constants" - "github.com/nitrictech/go-sdk/handler" + grpcx "github.com/nitrictech/go-sdk/internal/grpc" + "github.com/nitrictech/go-sdk/internal/handlers" + "github.com/nitrictech/go-sdk/nitric/errors" + "github.com/nitrictech/go-sdk/nitric/errors/codes" v1 "github.com/nitrictech/nitric/core/pkg/proto/websockets/v1" ) -type WebsocketWorker struct { +type websocketWorker struct { client v1.WebsocketHandlerClient registrationRequest *v1.RegistrationRequest - middleware handler.WebsocketMiddleware + handler handlers.Handler[Ctx] } -type WebsocketWorkerOpts struct { +type websocketWorkerOpts struct { RegistrationRequest *v1.RegistrationRequest - Middleware handler.WebsocketMiddleware + Handler handlers.Handler[Ctx] } // Start implements Worker. -func (w *WebsocketWorker) Start(ctx context.Context) error { +func (w *websocketWorker) Start(ctx context.Context) error { initReq := &v1.ClientMessage{ Content: &v1.ClientMessage_RegistrationRequest{ RegistrationRequest: w.registrationRequest, @@ -57,11 +55,11 @@ func (w *WebsocketWorker) Start(ctx context.Context) error { return err } for { - var ctx *handler.WebsocketContext + var ctx *Ctx resp, err := stream.Recv() - if err == io.EOF { + if errorsstd.Is(err, io.EOF) { err = stream.CloseSend() if err != nil { return err @@ -69,11 +67,10 @@ func (w *WebsocketWorker) Start(ctx context.Context) error { return nil } else if err == nil && resp.GetRegistrationResponse() != nil { - // Blob Notification has connected with Nitric server - fmt.Println("WebsocketWorker connected with Nitric server") + // There is no need to respond to the registration response } else if err == nil && resp.GetWebsocketEventRequest() != nil { - ctx = handler.NewWebsocketContext(resp) - ctx, err = w.middleware(ctx, handler.WebsocketDummy) + ctx = NewCtx(resp) + err = w.handler(ctx) if err != nil { ctx.WithError(err) } @@ -88,27 +85,21 @@ func (w *WebsocketWorker) Start(ctx context.Context) error { } } -func NewWebsocketWorker(opts *WebsocketWorkerOpts) *WebsocketWorker { - ctx, _ := context.WithTimeout(context.TODO(), constants.NitricDialTimeout()) - - conn, err := grpc.DialContext( - ctx, - constants.NitricAddress(), - constants.DefaultOptions()..., - ) +func newWebsocketWorker(opts *websocketWorkerOpts) *websocketWorker { + conn, err := grpcx.GetConnection() if err != nil { panic(errors.NewWithCause( codes.Unavailable, - "NewWebsocketWorker: Unable to reach StorageListenerClient", + "NewWebsocketWorker: Unable to reach WebsocketHandlerClient", err, )) } client := v1.NewWebsocketHandlerClient(conn) - return &WebsocketWorker{ + return &websocketWorker{ client: client, registrationRequest: opts.RegistrationRequest, - middleware: opts.Middleware, + handler: opts.Handler, } } diff --git a/nitric/manager.go b/nitric/workers/manager.go similarity index 54% rename from nitric/manager.go rename to nitric/workers/manager.go index d906655..3a55d33 100644 --- a/nitric/manager.go +++ b/nitric/workers/manager.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package nitric +package workers import ( "context" @@ -23,85 +23,55 @@ import ( "sync" multierror "github.com/missionMeteora/toolkit/errors" - "google.golang.org/grpc" - - apierrors "github.com/nitrictech/go-sdk/api/errors" - "github.com/nitrictech/go-sdk/api/keyvalue" - "github.com/nitrictech/go-sdk/api/queues" - "github.com/nitrictech/go-sdk/api/secrets" - "github.com/nitrictech/go-sdk/api/storage" - "github.com/nitrictech/go-sdk/api/topics" - "github.com/nitrictech/go-sdk/constants" - "github.com/nitrictech/go-sdk/workers" + + grpcx "github.com/nitrictech/go-sdk/internal/grpc" + apierrors "github.com/nitrictech/go-sdk/nitric/errors" v1 "github.com/nitrictech/nitric/core/pkg/proto/resources/v1" ) -// Manager is the top level object that resources are created on. -type Manager interface { - Run() error - addWorker(name string, s workers.Worker) - resourceServiceClient() (v1.ResourcesClient, error) - registerResource(request *v1.ResourceDeclareRequest) <-chan RegisterResult - registerPolicy(res *v1.ResourceIdentifier, actions ...v1.Action) (*manager, error) -} - type RegisterResult struct { Identifier *v1.ResourceIdentifier Err error } -type manager struct { - workers map[string]workers.Worker - conn grpc.ClientConnInterface - connMutex sync.Mutex - - rsc v1.ResourcesClient - topics topics.Topics - storage storage.Storage - secrets secrets.Secrets - queues queues.Queues - kvstores keyvalue.KeyValue +type Manager struct { + workers map[string]StreamWorker + + rsc v1.ResourcesClient } var defaultManager = New() +func GetDefaultManager() *Manager { + return defaultManager +} + // New is used to create the top level resource manager. // Note: this is not required if you are using // resources.NewApi() and the like. These use a default manager instance. -func New() Manager { - return &manager{ - workers: map[string]workers.Worker{}, +func New() *Manager { + return &Manager{ + workers: map[string]StreamWorker{}, } } -func (m *manager) addWorker(name string, s workers.Worker) { +func (m *Manager) AddWorker(name string, s StreamWorker) { m.workers[name] = s } -func (m *manager) resourceServiceClient() (v1.ResourcesClient, error) { - m.connMutex.Lock() - defer m.connMutex.Unlock() - - if m.conn == nil { - ctx, _ := context.WithTimeout(context.Background(), constants.NitricDialTimeout()) - - conn, err := grpc.DialContext( - ctx, - constants.NitricAddress(), - constants.DefaultOptions()..., - ) - if err != nil { - return nil, err - } - m.conn = conn +func (m *Manager) resourceServiceClient() (v1.ResourcesClient, error) { + conn, err := grpcx.GetConnection() + if err != nil { + return nil, err } + if m.rsc == nil { - m.rsc = v1.NewResourcesClient(m.conn) + m.rsc = v1.NewResourcesClient(conn) } return m.rsc, nil } -func (m *manager) registerResource(request *v1.ResourceDeclareRequest) <-chan RegisterResult { +func (m *Manager) RegisterResource(request *v1.ResourceDeclareRequest) <-chan RegisterResult { registerResourceChan := make(chan RegisterResult) go func() { @@ -134,36 +104,50 @@ func (m *manager) registerResource(request *v1.ResourceDeclareRequest) <-chan Re return registerResourceChan } -func (m *manager) registerPolicy(res *v1.ResourceIdentifier, actions ...v1.Action) (*manager, error) { +func functionResourceDeclareRequest(subject *v1.ResourceIdentifier, actions []v1.Action) *v1.ResourceDeclareRequest { + return &v1.ResourceDeclareRequest{ + Id: &v1.ResourceIdentifier{ + Type: v1.ResourceType_Policy, + }, + Config: &v1.ResourceDeclareRequest_Policy{ + Policy: &v1.PolicyResource{ + Principals: []*v1.ResourceIdentifier{ + { + Type: v1.ResourceType_Service, + }, + }, + Actions: actions, + Resources: []*v1.ResourceIdentifier{subject}, + }, + }, + } +} + +func (m *Manager) RegisterPolicy(res *v1.ResourceIdentifier, actions ...v1.Action) error { rsc, err := m.resourceServiceClient() if err != nil { - return m, err + return err } _, err = rsc.Declare(context.Background(), functionResourceDeclareRequest(res, actions)) if err != nil { - return m, err + return err } - return m, nil -} - -// Run will run the function and callback the required handlers when these events are received. -func Run() error { - return defaultManager.Run() + return nil } -func (m *manager) Run() error { +func (m *Manager) Run() error { wg := sync.WaitGroup{} errList := &multierror.ErrorList{} for _, worker := range m.workers { wg.Add(1) - go func(s workers.Worker) { + go func(s StreamWorker) { defer wg.Done() if err := s.Start(context.TODO()); err != nil { - if isBuildEnvirnonment() && isEOF(err) { + if isBuildEnvironment() && isEOF(err) { // ignore the EOF error when running code-as-config. return } @@ -178,8 +162,8 @@ func (m *manager) Run() error { return errList.Err() } -// IsBuildEnvirnonment will return true if the code is running during config discovery. -func isBuildEnvirnonment() bool { +// IsBuildEnvironment will return true if the code is running during config discovery. +func isBuildEnvironment() bool { return strings.ToLower(os.Getenv("NITRIC_ENVIRONMENT")) == "build" } diff --git a/workers/workers.go b/nitric/workers/workers.go similarity index 95% rename from workers/workers.go rename to nitric/workers/workers.go index c740611..a8d0f81 100644 --- a/workers/workers.go +++ b/nitric/workers/workers.go @@ -16,6 +16,6 @@ package workers import "context" -type Worker interface { +type StreamWorker interface { Start(context.Context) error } diff --git a/tools/tools.go b/tools/tools.go index f34dec9..444d855 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -12,6 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build tools +// +build tools + package tools import (