From 25b77757c1e6f372e03bf99ab7461264bba48d26 Mon Sep 17 00:00:00 2001 From: Cody Oss <6331106+codyoss@users.noreply.github.com> Date: Fri, 24 Jun 2022 12:01:18 -0500 Subject: [PATCH] chore: start generating REST clients for betas (#6248) Start generating as many regapic clients as possible for beta/alpha surfaces. There are some clients that produce known issues while generating and these have been excluded from this batch and being tracked elsewhere seperatly. Changes: feat(analytics): start generating REST client for beta clients feat(area120): start generating REST client for beta clients feat(asset): start generating REST client for beta clients feat(assuredworkloads): start generating REST client for beta clients feat(automl): start generating REST client for beta clients feat(bigquery): start generating REST client for beta clients feat(binaryauthorization): start generating REST client for beta clients feat(cloudtasks): start generating REST client for beta clients feat(containeranalysis): start generating REST client for beta clients feat(dataflow): start generating REST client for beta clients feat(dataqna): start generating REST client for beta clients feat(datastream): start generating REST client for beta clients feat(dialogflow): start generating REST client for beta clients feat(domains): start generating REST client for beta clients feat(errorreporting): start generating REST client for beta clients feat(gkehub): start generating REST client for beta clients feat(language): start generating REST client for beta clients feat(lifesciences): start generating REST client for beta clients feat(memcache): start generating REST client for beta clients feat(metastore): start generating REST client for beta clients feat(osconfig): start generating REST client for beta clients feat(oslogin): start generating REST client for beta clients feat(phishingprotection): start generating REST client for beta clients feat(privatecatalog): start generating REST client for beta clients feat(recaptchaenterprise): start generating REST client for beta clients feat(recommender): start generating REST client for beta clients feat(redis): start generating REST client for beta clients feat(scheduler): start generating REST client for beta clients feat(secretmanager): start generating REST client for beta clients feat(servicedirectory): start generating REST client for beta clients feat(speech): start generating REST client for beta clients feat(talent): start generating REST client for beta clients feat(videointelligence): start generating REST client for beta clients feat(vision): start generating REST client for beta clients feat(webrisk): start generating REST client for beta clients feat(workflows): start generating REST client for beta clients --- .../apiv1alpha/analytics_admin_client.go | 8215 ++++++++++++++--- .../analytics_admin_client_example_test.go | 12 + analytics/admin/apiv1alpha/doc.go | 21 + .../admin/apiv1alpha/gapic_metadata.json | 360 + area120/tables/apiv1alpha1/doc.go | 21 + .../tables/apiv1alpha1/gapic_metadata.json | 65 + area120/tables/apiv1alpha1/tables_client.go | 866 ++ .../apiv1alpha1/tables_client_example_test.go | 12 + asset/apiv1p2beta1/asset_client.go | 374 + .../apiv1p2beta1/asset_client_example_test.go | 12 + asset/apiv1p2beta1/doc.go | 21 + asset/apiv1p2beta1/gapic_metadata.json | 30 + asset/apiv1p5beta1/asset_client.go | 189 + .../apiv1p5beta1/asset_client_example_test.go | 12 + asset/apiv1p5beta1/doc.go | 21 + asset/apiv1p5beta1/gapic_metadata.json | 10 + .../apiv1beta1/assured_workloads_client.go | 469 +- .../assured_workloads_client_example_test.go | 12 + assuredworkloads/apiv1beta1/doc.go | 21 + .../apiv1beta1/gapic_metadata.json | 30 + automl/apiv1beta1/auto_ml_client.go | 2189 ++++- .../apiv1beta1/auto_ml_client_example_test.go | 12 + automl/apiv1beta1/doc.go | 21 + automl/apiv1beta1/gapic_metadata.json | 140 + automl/apiv1beta1/prediction_client.go | 277 +- .../prediction_client_example_test.go | 12 + .../apiv1beta1/connection_client.go | 634 ++ .../connection_client_example_test.go | 12 + bigquery/connection/apiv1beta1/doc.go | 21 + .../connection/apiv1beta1/gapic_metadata.json | 50 + .../apiv1beta1/analytics_hub_client.go | 1191 +++ .../analytics_hub_client_example_test.go | 12 + bigquery/dataexchange/apiv1beta1/doc.go | 21 + .../apiv1beta1/gapic_metadata.json | 80 + .../apiv1beta1/big_query_storage_client.go | 500 + .../big_query_storage_client_example_test.go | 12 + bigquery/storage/apiv1beta1/doc.go | 21 + .../storage/apiv1beta1/gapic_metadata.json | 30 + .../apiv1beta2/big_query_read_client.go | 370 + .../big_query_read_client_example_test.go | 12 + .../apiv1beta2/big_query_write_client.go | 483 + .../big_query_write_client_example_test.go | 12 + bigquery/storage/apiv1beta2/doc.go | 21 + .../storage/apiv1beta2/gapic_metadata.json | 55 + ...uthz_management_service_v1_beta1_client.go | 583 ++ ...nt_service_v1_beta1_client_example_test.go | 12 + binaryauthorization/apiv1beta1/doc.go | 21 + .../apiv1beta1/gapic_metadata.json | 50 + .../system_policy_v1_beta1_client.go | 132 + ...tem_policy_v1_beta1_client_example_test.go | 12 + cloudtasks/apiv2beta2/cloud_tasks_client.go | 1543 ++++ .../cloud_tasks_client_example_test.go | 12 + cloudtasks/apiv2beta2/doc.go | 21 + cloudtasks/apiv2beta2/gapic_metadata.json | 105 + cloudtasks/apiv2beta3/cloud_tasks_client.go | 1273 +++ .../cloud_tasks_client_example_test.go | 12 + cloudtasks/apiv2beta3/doc.go | 21 + cloudtasks/apiv2beta3/gapic_metadata.json | 85 + .../container_analysis_v1_beta1_client.go | 515 ++ ...r_analysis_v1_beta1_client_example_test.go | 12 + containeranalysis/apiv1beta1/doc.go | 21 + .../apiv1beta1/gapic_metadata.json | 80 + .../apiv1beta1/grafeas_v1_beta1_client.go | 1140 +++ .../grafeas_v1_beta1_client_example_test.go | 12 + dataflow/apiv1beta3/doc.go | 21 + dataflow/apiv1beta3/flex_templates_client.go | 139 + .../flex_templates_client_example_test.go | 12 + dataflow/apiv1beta3/gapic_metadata.json | 120 + dataflow/apiv1beta3/jobs_v1_beta3_client.go | 608 ++ .../jobs_v1_beta3_client_example_test.go | 12 + .../apiv1beta3/messages_v1_beta3_client.go | 188 + .../messages_v1_beta3_client_example_test.go | 12 + .../apiv1beta3/metrics_v1_beta3_client.go | 342 + .../metrics_v1_beta3_client_example_test.go | 12 + .../apiv1beta3/snapshots_v1_beta3_client.go | 240 + .../snapshots_v1_beta3_client_example_test.go | 12 + dataflow/apiv1beta3/templates_client.go | 280 + .../templates_client_example_test.go | 12 + dataqna/apiv1alpha/auto_suggestion_client.go | 154 + .../auto_suggestion_client_example_test.go | 12 + dataqna/apiv1alpha/doc.go | 21 + dataqna/apiv1alpha/gapic_metadata.json | 40 + dataqna/apiv1alpha/question_client.go | 416 + .../question_client_example_test.go | 12 + dataqna/go.mod | 1 + datastream/apiv1alpha1/datastream_client.go | 1980 +++- .../datastream_client_example_test.go | 12 + datastream/apiv1alpha1/doc.go | 21 + datastream/apiv1alpha1/gapic_metadata.json | 110 + dialogflow/cx/apiv3beta1/agents_client.go | 1234 ++- .../apiv3beta1/agents_client_example_test.go | 12 + dialogflow/cx/apiv3beta1/changelogs_client.go | 567 ++ .../changelogs_client_example_test.go | 12 + .../cx/apiv3beta1/deployments_client.go | 564 ++ .../deployments_client_example_test.go | 12 + dialogflow/cx/apiv3beta1/doc.go | 21 + .../cx/apiv3beta1/entity_types_client.go | 792 ++ .../entity_types_client_example_test.go | 12 + .../cx/apiv3beta1/environments_client.go | 1364 ++- .../environments_client_example_test.go | 12 + .../cx/apiv3beta1/experiments_client.go | 897 ++ .../experiments_client_example_test.go | 12 + dialogflow/cx/apiv3beta1/flows_client.go | 1443 ++- .../apiv3beta1/flows_client_example_test.go | 12 + dialogflow/cx/apiv3beta1/gapic_metadata.json | 1363 ++- dialogflow/cx/apiv3beta1/intents_client.go | 792 ++ .../apiv3beta1/intents_client_example_test.go | 12 + dialogflow/cx/apiv3beta1/pages_client.go | 784 ++ .../apiv3beta1/pages_client_example_test.go | 12 + .../cx/apiv3beta1/security_settings_client.go | 758 ++ .../security_settings_client_example_test.go | 12 + .../apiv3beta1/session_entity_types_client.go | 757 ++ ...ession_entity_types_client_example_test.go | 12 + dialogflow/cx/apiv3beta1/sessions_client.go | 636 ++ .../sessions_client_example_test.go | 12 + dialogflow/cx/apiv3beta1/test_cases_client.go | 1516 ++- .../test_cases_client_example_test.go | 12 + .../transition_route_groups_client.go | 796 ++ ...sition_route_groups_client_example_test.go | 12 + dialogflow/cx/apiv3beta1/versions_client.go | 1082 ++- .../versions_client_example_test.go | 12 + dialogflow/cx/apiv3beta1/webhooks_client.go | 764 ++ .../webhooks_client_example_test.go | 12 + domains/apiv1beta1/doc.go | 21 + domains/apiv1beta1/domains_client.go | 1473 ++- .../apiv1beta1/domains_client_example_test.go | 12 + domains/apiv1beta1/gapic_metadata.json | 80 + errorreporting/apiv1beta1/doc.go | 21 + .../apiv1beta1/error_group_client.go | 215 + .../error_group_client_example_test.go | 12 + .../apiv1beta1/error_stats_client.go | 385 + .../error_stats_client_example_test.go | 12 + errorreporting/apiv1beta1/gapic_metadata.json | 45 + .../apiv1beta1/report_errors_client.go | 155 + .../report_errors_client_example_test.go | 12 + gkehub/apiv1beta1/doc.go | 21 + gkehub/apiv1beta1/gapic_metadata.json | 90 + .../apiv1beta1/gke_hub_membership_client.go | 1503 ++- .../gke_hub_membership_client_example_test.go | 12 + internal/gapicgen/generator/config.go | 47 + language/apiv1beta2/doc.go | 21 + language/apiv1beta2/gapic_metadata.json | 35 + language/apiv1beta2/language_client.go | 496 + .../language_client_example_test.go | 12 + language/go.mod | 1 + lifesciences/apiv2beta/doc.go | 21 + lifesciences/apiv2beta/gapic_metadata.json | 10 + .../workflows_service_v2_beta_client.go | 190 +- ...ows_service_v2_beta_client_example_test.go | 12 + lifesciences/go.mod | 1 + memcache/apiv1beta2/cloud_memcache_client.go | 746 +- .../cloud_memcache_client_example_test.go | 12 + memcache/apiv1beta2/doc.go | 21 + memcache/apiv1beta2/gapic_metadata.json | 45 + .../apiv1beta/dataproc_metastore_client.go | 1494 ++- .../dataproc_metastore_client_example_test.go | 12 + metastore/apiv1beta/doc.go | 21 + metastore/apiv1beta/gapic_metadata.json | 80 + .../apiv1beta/agent_endpoint_client.go | 560 ++ .../agent_endpoint_client_example_test.go | 12 + osconfig/agentendpoint/apiv1beta/doc.go | 21 + .../apiv1beta/gapic_metadata.json | 35 + osconfig/apiv1alpha/doc.go | 21 + osconfig/apiv1alpha/gapic_metadata.json | 75 + osconfig/apiv1alpha/os_config_zonal_client.go | 1465 ++- .../os_config_zonal_client_example_test.go | 12 + osconfig/apiv1beta/doc.go | 21 + osconfig/apiv1beta/gapic_metadata.json | 95 + osconfig/apiv1beta/os_config_client.go | 1409 +++ .../os_config_client_example_test.go | 12 + oslogin/apiv1beta/doc.go | 21 + oslogin/apiv1beta/gapic_metadata.json | 35 + oslogin/apiv1beta/os_login_client.go | 472 + .../apiv1beta/os_login_client_example_test.go | 12 + oslogin/go.mod | 1 + phishingprotection/apiv1beta1/doc.go | 21 + .../apiv1beta1/gapic_metadata.json | 10 + ...hing_protection_service_v1_beta1_client.go | 145 + ...on_service_v1_beta1_client_example_test.go | 12 + phishingprotection/go.mod | 1 + privatecatalog/apiv1beta1/doc.go | 21 + privatecatalog/apiv1beta1/gapic_metadata.json | 20 + .../apiv1beta1/private_catalog_client.go | 372 + .../private_catalog_client_example_test.go | 12 + recaptchaenterprise/apiv1beta1/doc.go | 21 + .../apiv1beta1/gapic_metadata.json | 15 + ...tcha_enterprise_service_v1_beta1_client.go | 201 + ...se_service_v1_beta1_client_example_test.go | 12 + recommender/apiv1beta1/doc.go | 21 + recommender/apiv1beta1/gapic_metadata.json | 65 + recommender/apiv1beta1/recommender_client.go | 944 ++ .../recommender_client_example_test.go | 12 + redis/apiv1beta1/cloud_redis_client.go | 1128 ++- .../cloud_redis_client_example_test.go | 12 + redis/apiv1beta1/doc.go | 21 + redis/apiv1beta1/gapic_metadata.json | 60 + .../apiv1beta1/cloud_scheduler_client.go | 639 ++ .../cloud_scheduler_client_example_test.go | 12 + scheduler/apiv1beta1/doc.go | 21 + scheduler/apiv1beta1/gapic_metadata.json | 45 + secretmanager/apiv1beta1/doc.go | 21 + secretmanager/apiv1beta1/gapic_metadata.json | 80 + .../apiv1beta1/secret_manager_client.go | 1054 +++ .../secret_manager_client_example_test.go | 12 + servicedirectory/apiv1beta1/doc.go | 21 + .../apiv1beta1/gapic_metadata.json | 105 + servicedirectory/apiv1beta1/lookup_client.go | 151 + .../apiv1beta1/lookup_client_example_test.go | 12 + .../apiv1beta1/registration_client.go | 1409 +++ .../registration_client_example_test.go | 12 + speech/apiv1p1beta1/adaptation_client.go | 693 ++ .../adaptation_client_example_test.go | 12 + speech/apiv1p1beta1/doc.go | 21 + speech/apiv1p1beta1/gapic_metadata.json | 75 + speech/apiv1p1beta1/speech_client.go | 264 +- .../speech_client_example_test.go | 12 + talent/apiv4beta1/company_client.go | 465 + .../apiv4beta1/company_client_example_test.go | 12 + talent/apiv4beta1/completion_client.go | 215 + .../completion_client_example_test.go | 12 + talent/apiv4beta1/doc.go | 21 + talent/apiv4beta1/event_client.go | 199 + .../apiv4beta1/event_client_example_test.go | 12 + talent/apiv4beta1/gapic_metadata.json | 160 + talent/apiv4beta1/job_client.go | 847 +- talent/apiv4beta1/job_client_example_test.go | 12 + talent/apiv4beta1/tenant_client.go | 461 + .../apiv4beta1/tenant_client_example_test.go | 12 + videointelligence/apiv1beta2/doc.go | 21 + .../apiv1beta2/gapic_metadata.json | 10 + .../apiv1beta2/video_intelligence_client.go | 186 +- .../video_intelligence_client_example_test.go | 12 + videointelligence/go.mod | 1 + vision/apiv1p1beta1/doc.go | 21 + vision/apiv1p1beta1/gapic_metadata.json | 10 + vision/apiv1p1beta1/image_annotator_client.go | 151 + .../image_annotator_client_example_test.go | 12 + webrisk/apiv1beta1/doc.go | 21 + webrisk/apiv1beta1/gapic_metadata.json | 20 + .../web_risk_service_v1_beta1_client.go | 306 + ...sk_service_v1_beta1_client_example_test.go | 12 + webrisk/go.mod | 1 + workflows/apiv1beta/doc.go | 21 + workflows/apiv1beta/gapic_metadata.json | 30 + workflows/apiv1beta/workflows_client.go | 498 +- .../workflows_client_example_test.go | 12 + workflows/executions/apiv1beta/doc.go | 21 + .../executions/apiv1beta/executions_client.go | 356 + .../executions_client_example_test.go | 12 + .../executions/apiv1beta/gapic_metadata.json | 25 + 250 files changed, 64758 insertions(+), 2585 deletions(-) diff --git a/analytics/admin/apiv1alpha/analytics_admin_client.go b/analytics/admin/apiv1alpha/analytics_admin_client.go index 772155e8798c..ee5f6e8d12bc 100644 --- a/analytics/admin/apiv1alpha/analytics_admin_client.go +++ b/analytics/admin/apiv1alpha/analytics_admin_client.go @@ -17,21 +17,27 @@ package admin import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" adminpb "google.golang.org/genproto/googleapis/analytics/admin/v1alpha" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -981,6 +987,792 @@ func defaultAnalyticsAdminCallOptions() *AnalyticsAdminCallOptions { } } +func defaultAnalyticsAdminRESTCallOptions() *AnalyticsAdminCallOptions { + return &AnalyticsAdminCallOptions{ + GetAccount: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListAccounts: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DeleteAccount: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateAccount: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ProvisionAccountTicket: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListAccountSummaries: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetProperty: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListProperties: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CreateProperty: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DeleteProperty: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateProperty: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetUserLink: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + BatchGetUserLinks: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListUserLinks: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + AuditUserLinks: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CreateUserLink: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + BatchCreateUserLinks: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateUserLink: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + BatchUpdateUserLinks: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DeleteUserLink: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + BatchDeleteUserLinks: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CreateFirebaseLink: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DeleteFirebaseLink: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListFirebaseLinks: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetGlobalSiteTag: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CreateGoogleAdsLink: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateGoogleAdsLink: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DeleteGoogleAdsLink: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListGoogleAdsLinks: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetDataSharingSettings: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetMeasurementProtocolSecret: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListMeasurementProtocolSecrets: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CreateMeasurementProtocolSecret: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DeleteMeasurementProtocolSecret: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateMeasurementProtocolSecret: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + AcknowledgeUserDataCollection: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + SearchChangeHistoryEvents: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetGoogleSignalsSettings: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateGoogleSignalsSettings: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CreateConversionEvent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetConversionEvent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DeleteConversionEvent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListConversionEvents: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetDisplayVideo360AdvertiserLink: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListDisplayVideo360AdvertiserLinks: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CreateDisplayVideo360AdvertiserLink: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DeleteDisplayVideo360AdvertiserLink: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateDisplayVideo360AdvertiserLink: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetDisplayVideo360AdvertiserLinkProposal: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListDisplayVideo360AdvertiserLinkProposals: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CreateDisplayVideo360AdvertiserLinkProposal: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DeleteDisplayVideo360AdvertiserLinkProposal: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ApproveDisplayVideo360AdvertiserLinkProposal: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CancelDisplayVideo360AdvertiserLinkProposal: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CreateCustomDimension: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateCustomDimension: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListCustomDimensions: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ArchiveCustomDimension: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetCustomDimension: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CreateCustomMetric: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateCustomMetric: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListCustomMetrics: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ArchiveCustomMetric: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetCustomMetric: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetDataRetentionSettings: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateDataRetentionSettings: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CreateDataStream: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DeleteDataStream: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateDataStream: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListDataStreams: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetDataStream: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + } +} + // internalAnalyticsAdminClient is an interface that defines the methods available from Google Analytics Admin API. type internalAnalyticsAdminClient interface { Close() error @@ -1059,43 +1851,2512 @@ type internalAnalyticsAdminClient interface { GetDataStream(context.Context, *adminpb.GetDataStreamRequest, ...gax.CallOption) (*adminpb.DataStream, error) } -// AnalyticsAdminClient is a client for interacting with Google Analytics Admin API. -// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. -// -// Service Interface for the Analytics Admin API (GA4). -type AnalyticsAdminClient struct { - // The internal transport-dependent client. - internalClient internalAnalyticsAdminClient +// AnalyticsAdminClient is a client for interacting with Google Analytics Admin API. +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +// +// Service Interface for the Analytics Admin API (GA4). +type AnalyticsAdminClient struct { + // The internal transport-dependent client. + internalClient internalAnalyticsAdminClient + + // The call options for this service. + CallOptions *AnalyticsAdminCallOptions +} + +// Wrapper methods routed to the internal client. + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *AnalyticsAdminClient) Close() error { + return c.internalClient.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *AnalyticsAdminClient) setGoogleClientInfo(keyval ...string) { + c.internalClient.setGoogleClientInfo(keyval...) +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *AnalyticsAdminClient) Connection() *grpc.ClientConn { + return c.internalClient.Connection() +} + +// GetAccount lookup for a single Account. +func (c *AnalyticsAdminClient) GetAccount(ctx context.Context, req *adminpb.GetAccountRequest, opts ...gax.CallOption) (*adminpb.Account, error) { + return c.internalClient.GetAccount(ctx, req, opts...) +} + +// ListAccounts returns all accounts accessible by the caller. +// +// Note that these accounts might not currently have GA4 properties. +// Soft-deleted (ie: “trashed”) accounts are excluded by default. +// Returns an empty list if no relevant accounts are found. +func (c *AnalyticsAdminClient) ListAccounts(ctx context.Context, req *adminpb.ListAccountsRequest, opts ...gax.CallOption) *AccountIterator { + return c.internalClient.ListAccounts(ctx, req, opts...) +} + +// DeleteAccount marks target Account as soft-deleted (ie: “trashed”) and returns it. +// +// This API does not have a method to restore soft-deleted accounts. +// However, they can be restored using the Trash Can UI. +// +// If the accounts are not restored before the expiration time, the account +// and all child resources (eg: Properties, GoogleAdsLinks, Streams, +// UserLinks) will be permanently purged. +// https://support.google.com/analytics/answer/6154772 (at https://support.google.com/analytics/answer/6154772) +// +// Returns an error if the target is not found. +func (c *AnalyticsAdminClient) DeleteAccount(ctx context.Context, req *adminpb.DeleteAccountRequest, opts ...gax.CallOption) error { + return c.internalClient.DeleteAccount(ctx, req, opts...) +} + +// UpdateAccount updates an account. +func (c *AnalyticsAdminClient) UpdateAccount(ctx context.Context, req *adminpb.UpdateAccountRequest, opts ...gax.CallOption) (*adminpb.Account, error) { + return c.internalClient.UpdateAccount(ctx, req, opts...) +} + +// ProvisionAccountTicket requests a ticket for creating an account. +func (c *AnalyticsAdminClient) ProvisionAccountTicket(ctx context.Context, req *adminpb.ProvisionAccountTicketRequest, opts ...gax.CallOption) (*adminpb.ProvisionAccountTicketResponse, error) { + return c.internalClient.ProvisionAccountTicket(ctx, req, opts...) +} + +// ListAccountSummaries returns summaries of all accounts accessible by the caller. +func (c *AnalyticsAdminClient) ListAccountSummaries(ctx context.Context, req *adminpb.ListAccountSummariesRequest, opts ...gax.CallOption) *AccountSummaryIterator { + return c.internalClient.ListAccountSummaries(ctx, req, opts...) +} + +// GetProperty lookup for a single “GA4” Property. +func (c *AnalyticsAdminClient) GetProperty(ctx context.Context, req *adminpb.GetPropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { + return c.internalClient.GetProperty(ctx, req, opts...) +} + +// ListProperties returns child Properties under the specified parent Account. +// +// Only “GA4” properties will be returned. +// Properties will be excluded if the caller does not have access. +// Soft-deleted (ie: “trashed”) properties are excluded by default. +// Returns an empty list if no relevant properties are found. +func (c *AnalyticsAdminClient) ListProperties(ctx context.Context, req *adminpb.ListPropertiesRequest, opts ...gax.CallOption) *PropertyIterator { + return c.internalClient.ListProperties(ctx, req, opts...) +} + +// CreateProperty creates an “GA4” property with the specified location and attributes. +func (c *AnalyticsAdminClient) CreateProperty(ctx context.Context, req *adminpb.CreatePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { + return c.internalClient.CreateProperty(ctx, req, opts...) +} + +// DeleteProperty marks target Property as soft-deleted (ie: “trashed”) and returns it. +// +// This API does not have a method to restore soft-deleted properties. +// However, they can be restored using the Trash Can UI. +// +// If the properties are not restored before the expiration time, the Property +// and all child resources (eg: GoogleAdsLinks, Streams, UserLinks) +// will be permanently purged. +// https://support.google.com/analytics/answer/6154772 (at https://support.google.com/analytics/answer/6154772) +// +// Returns an error if the target is not found, or is not an GA4 Property. +func (c *AnalyticsAdminClient) DeleteProperty(ctx context.Context, req *adminpb.DeletePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { + return c.internalClient.DeleteProperty(ctx, req, opts...) +} + +// UpdateProperty updates a property. +func (c *AnalyticsAdminClient) UpdateProperty(ctx context.Context, req *adminpb.UpdatePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { + return c.internalClient.UpdateProperty(ctx, req, opts...) +} + +// GetUserLink gets information about a user’s link to an account or property. +func (c *AnalyticsAdminClient) GetUserLink(ctx context.Context, req *adminpb.GetUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { + return c.internalClient.GetUserLink(ctx, req, opts...) +} + +// BatchGetUserLinks gets information about multiple users’ links to an account or property. +func (c *AnalyticsAdminClient) BatchGetUserLinks(ctx context.Context, req *adminpb.BatchGetUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchGetUserLinksResponse, error) { + return c.internalClient.BatchGetUserLinks(ctx, req, opts...) +} + +// ListUserLinks lists all user links on an account or property. +func (c *AnalyticsAdminClient) ListUserLinks(ctx context.Context, req *adminpb.ListUserLinksRequest, opts ...gax.CallOption) *UserLinkIterator { + return c.internalClient.ListUserLinks(ctx, req, opts...) +} + +// AuditUserLinks lists all user links on an account or property, including implicit ones +// that come from effective permissions granted by groups or organization +// admin roles. +// +// If a returned user link does not have direct permissions, they cannot +// be removed from the account or property directly with the DeleteUserLink +// command. They have to be removed from the group/etc that gives them +// permissions, which is currently only usable/discoverable in the GA or GMP +// UIs. +func (c *AnalyticsAdminClient) AuditUserLinks(ctx context.Context, req *adminpb.AuditUserLinksRequest, opts ...gax.CallOption) *AuditUserLinkIterator { + return c.internalClient.AuditUserLinks(ctx, req, opts...) +} + +// CreateUserLink creates a user link on an account or property. +// +// If the user with the specified email already has permissions on the +// account or property, then the user’s existing permissions will be unioned +// with the permissions specified in the new UserLink. +func (c *AnalyticsAdminClient) CreateUserLink(ctx context.Context, req *adminpb.CreateUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { + return c.internalClient.CreateUserLink(ctx, req, opts...) +} + +// BatchCreateUserLinks creates information about multiple users’ links to an account or property. +// +// This method is transactional. If any UserLink cannot be created, none of +// the UserLinks will be created. +func (c *AnalyticsAdminClient) BatchCreateUserLinks(ctx context.Context, req *adminpb.BatchCreateUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchCreateUserLinksResponse, error) { + return c.internalClient.BatchCreateUserLinks(ctx, req, opts...) +} + +// UpdateUserLink updates a user link on an account or property. +func (c *AnalyticsAdminClient) UpdateUserLink(ctx context.Context, req *adminpb.UpdateUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { + return c.internalClient.UpdateUserLink(ctx, req, opts...) +} + +// BatchUpdateUserLinks updates information about multiple users’ links to an account or property. +func (c *AnalyticsAdminClient) BatchUpdateUserLinks(ctx context.Context, req *adminpb.BatchUpdateUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchUpdateUserLinksResponse, error) { + return c.internalClient.BatchUpdateUserLinks(ctx, req, opts...) +} + +// DeleteUserLink deletes a user link on an account or property. +func (c *AnalyticsAdminClient) DeleteUserLink(ctx context.Context, req *adminpb.DeleteUserLinkRequest, opts ...gax.CallOption) error { + return c.internalClient.DeleteUserLink(ctx, req, opts...) +} + +// BatchDeleteUserLinks deletes information about multiple users’ links to an account or property. +func (c *AnalyticsAdminClient) BatchDeleteUserLinks(ctx context.Context, req *adminpb.BatchDeleteUserLinksRequest, opts ...gax.CallOption) error { + return c.internalClient.BatchDeleteUserLinks(ctx, req, opts...) +} + +// CreateFirebaseLink creates a FirebaseLink. +// +// Properties can have at most one FirebaseLink. +func (c *AnalyticsAdminClient) CreateFirebaseLink(ctx context.Context, req *adminpb.CreateFirebaseLinkRequest, opts ...gax.CallOption) (*adminpb.FirebaseLink, error) { + return c.internalClient.CreateFirebaseLink(ctx, req, opts...) +} + +// DeleteFirebaseLink deletes a FirebaseLink on a property +func (c *AnalyticsAdminClient) DeleteFirebaseLink(ctx context.Context, req *adminpb.DeleteFirebaseLinkRequest, opts ...gax.CallOption) error { + return c.internalClient.DeleteFirebaseLink(ctx, req, opts...) +} + +// ListFirebaseLinks lists FirebaseLinks on a property. +// Properties can have at most one FirebaseLink. +func (c *AnalyticsAdminClient) ListFirebaseLinks(ctx context.Context, req *adminpb.ListFirebaseLinksRequest, opts ...gax.CallOption) *FirebaseLinkIterator { + return c.internalClient.ListFirebaseLinks(ctx, req, opts...) +} + +// GetGlobalSiteTag returns the Site Tag for the specified web stream. +// Site Tags are immutable singletons. +func (c *AnalyticsAdminClient) GetGlobalSiteTag(ctx context.Context, req *adminpb.GetGlobalSiteTagRequest, opts ...gax.CallOption) (*adminpb.GlobalSiteTag, error) { + return c.internalClient.GetGlobalSiteTag(ctx, req, opts...) +} + +// CreateGoogleAdsLink creates a GoogleAdsLink. +func (c *AnalyticsAdminClient) CreateGoogleAdsLink(ctx context.Context, req *adminpb.CreateGoogleAdsLinkRequest, opts ...gax.CallOption) (*adminpb.GoogleAdsLink, error) { + return c.internalClient.CreateGoogleAdsLink(ctx, req, opts...) +} + +// UpdateGoogleAdsLink updates a GoogleAdsLink on a property +func (c *AnalyticsAdminClient) UpdateGoogleAdsLink(ctx context.Context, req *adminpb.UpdateGoogleAdsLinkRequest, opts ...gax.CallOption) (*adminpb.GoogleAdsLink, error) { + return c.internalClient.UpdateGoogleAdsLink(ctx, req, opts...) +} + +// DeleteGoogleAdsLink deletes a GoogleAdsLink on a property +func (c *AnalyticsAdminClient) DeleteGoogleAdsLink(ctx context.Context, req *adminpb.DeleteGoogleAdsLinkRequest, opts ...gax.CallOption) error { + return c.internalClient.DeleteGoogleAdsLink(ctx, req, opts...) +} + +// ListGoogleAdsLinks lists GoogleAdsLinks on a property. +func (c *AnalyticsAdminClient) ListGoogleAdsLinks(ctx context.Context, req *adminpb.ListGoogleAdsLinksRequest, opts ...gax.CallOption) *GoogleAdsLinkIterator { + return c.internalClient.ListGoogleAdsLinks(ctx, req, opts...) +} + +// GetDataSharingSettings get data sharing settings on an account. +// Data sharing settings are singletons. +func (c *AnalyticsAdminClient) GetDataSharingSettings(ctx context.Context, req *adminpb.GetDataSharingSettingsRequest, opts ...gax.CallOption) (*adminpb.DataSharingSettings, error) { + return c.internalClient.GetDataSharingSettings(ctx, req, opts...) +} + +// GetMeasurementProtocolSecret lookup for a single “GA4” MeasurementProtocolSecret. +func (c *AnalyticsAdminClient) GetMeasurementProtocolSecret(ctx context.Context, req *adminpb.GetMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { + return c.internalClient.GetMeasurementProtocolSecret(ctx, req, opts...) +} + +// ListMeasurementProtocolSecrets returns child MeasurementProtocolSecrets under the specified parent +// Property. +func (c *AnalyticsAdminClient) ListMeasurementProtocolSecrets(ctx context.Context, req *adminpb.ListMeasurementProtocolSecretsRequest, opts ...gax.CallOption) *MeasurementProtocolSecretIterator { + return c.internalClient.ListMeasurementProtocolSecrets(ctx, req, opts...) +} + +// CreateMeasurementProtocolSecret creates a measurement protocol secret. +func (c *AnalyticsAdminClient) CreateMeasurementProtocolSecret(ctx context.Context, req *adminpb.CreateMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { + return c.internalClient.CreateMeasurementProtocolSecret(ctx, req, opts...) +} + +// DeleteMeasurementProtocolSecret deletes target MeasurementProtocolSecret. +func (c *AnalyticsAdminClient) DeleteMeasurementProtocolSecret(ctx context.Context, req *adminpb.DeleteMeasurementProtocolSecretRequest, opts ...gax.CallOption) error { + return c.internalClient.DeleteMeasurementProtocolSecret(ctx, req, opts...) +} + +// UpdateMeasurementProtocolSecret updates a measurement protocol secret. +func (c *AnalyticsAdminClient) UpdateMeasurementProtocolSecret(ctx context.Context, req *adminpb.UpdateMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { + return c.internalClient.UpdateMeasurementProtocolSecret(ctx, req, opts...) +} + +// AcknowledgeUserDataCollection acknowledges the terms of user data collection for the specified property. +// +// This acknowledgement must be completed (either in the Google Analytics UI +// or via this API) before MeasurementProtocolSecret resources may be created. +func (c *AnalyticsAdminClient) AcknowledgeUserDataCollection(ctx context.Context, req *adminpb.AcknowledgeUserDataCollectionRequest, opts ...gax.CallOption) (*adminpb.AcknowledgeUserDataCollectionResponse, error) { + return c.internalClient.AcknowledgeUserDataCollection(ctx, req, opts...) +} + +// SearchChangeHistoryEvents searches through all changes to an account or its children given the +// specified set of filters. +func (c *AnalyticsAdminClient) SearchChangeHistoryEvents(ctx context.Context, req *adminpb.SearchChangeHistoryEventsRequest, opts ...gax.CallOption) *ChangeHistoryEventIterator { + return c.internalClient.SearchChangeHistoryEvents(ctx, req, opts...) +} + +// GetGoogleSignalsSettings lookup for Google Signals settings for a property. +func (c *AnalyticsAdminClient) GetGoogleSignalsSettings(ctx context.Context, req *adminpb.GetGoogleSignalsSettingsRequest, opts ...gax.CallOption) (*adminpb.GoogleSignalsSettings, error) { + return c.internalClient.GetGoogleSignalsSettings(ctx, req, opts...) +} + +// UpdateGoogleSignalsSettings updates Google Signals settings for a property. +func (c *AnalyticsAdminClient) UpdateGoogleSignalsSettings(ctx context.Context, req *adminpb.UpdateGoogleSignalsSettingsRequest, opts ...gax.CallOption) (*adminpb.GoogleSignalsSettings, error) { + return c.internalClient.UpdateGoogleSignalsSettings(ctx, req, opts...) +} + +// CreateConversionEvent creates a conversion event with the specified attributes. +func (c *AnalyticsAdminClient) CreateConversionEvent(ctx context.Context, req *adminpb.CreateConversionEventRequest, opts ...gax.CallOption) (*adminpb.ConversionEvent, error) { + return c.internalClient.CreateConversionEvent(ctx, req, opts...) +} + +// GetConversionEvent retrieve a single conversion event. +func (c *AnalyticsAdminClient) GetConversionEvent(ctx context.Context, req *adminpb.GetConversionEventRequest, opts ...gax.CallOption) (*adminpb.ConversionEvent, error) { + return c.internalClient.GetConversionEvent(ctx, req, opts...) +} + +// DeleteConversionEvent deletes a conversion event in a property. +func (c *AnalyticsAdminClient) DeleteConversionEvent(ctx context.Context, req *adminpb.DeleteConversionEventRequest, opts ...gax.CallOption) error { + return c.internalClient.DeleteConversionEvent(ctx, req, opts...) +} + +// ListConversionEvents returns a list of conversion events in the specified parent property. +// +// Returns an empty list if no conversion events are found. +func (c *AnalyticsAdminClient) ListConversionEvents(ctx context.Context, req *adminpb.ListConversionEventsRequest, opts ...gax.CallOption) *ConversionEventIterator { + return c.internalClient.ListConversionEvents(ctx, req, opts...) +} + +// GetDisplayVideo360AdvertiserLink look up a single DisplayVideo360AdvertiserLink +func (c *AnalyticsAdminClient) GetDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.GetDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { + return c.internalClient.GetDisplayVideo360AdvertiserLink(ctx, req, opts...) +} + +// ListDisplayVideo360AdvertiserLinks lists all DisplayVideo360AdvertiserLinks on a property. +func (c *AnalyticsAdminClient) ListDisplayVideo360AdvertiserLinks(ctx context.Context, req *adminpb.ListDisplayVideo360AdvertiserLinksRequest, opts ...gax.CallOption) *DisplayVideo360AdvertiserLinkIterator { + return c.internalClient.ListDisplayVideo360AdvertiserLinks(ctx, req, opts...) +} + +// CreateDisplayVideo360AdvertiserLink creates a DisplayVideo360AdvertiserLink. +// This can only be utilized by users who have proper authorization both on +// the Google Analytics property and on the Display & Video 360 advertiser. +// Users who do not have access to the Display & Video 360 advertiser should +// instead seek to create a DisplayVideo360LinkProposal. +func (c *AnalyticsAdminClient) CreateDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.CreateDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { + return c.internalClient.CreateDisplayVideo360AdvertiserLink(ctx, req, opts...) +} + +// DeleteDisplayVideo360AdvertiserLink deletes a DisplayVideo360AdvertiserLink on a property. +func (c *AnalyticsAdminClient) DeleteDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.DeleteDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) error { + return c.internalClient.DeleteDisplayVideo360AdvertiserLink(ctx, req, opts...) +} + +// UpdateDisplayVideo360AdvertiserLink updates a DisplayVideo360AdvertiserLink on a property. +func (c *AnalyticsAdminClient) UpdateDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.UpdateDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { + return c.internalClient.UpdateDisplayVideo360AdvertiserLink(ctx, req, opts...) +} + +// GetDisplayVideo360AdvertiserLinkProposal lookup for a single DisplayVideo360AdvertiserLinkProposal. +func (c *AnalyticsAdminClient) GetDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.GetDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { + return c.internalClient.GetDisplayVideo360AdvertiserLinkProposal(ctx, req, opts...) +} + +// ListDisplayVideo360AdvertiserLinkProposals lists DisplayVideo360AdvertiserLinkProposals on a property. +func (c *AnalyticsAdminClient) ListDisplayVideo360AdvertiserLinkProposals(ctx context.Context, req *adminpb.ListDisplayVideo360AdvertiserLinkProposalsRequest, opts ...gax.CallOption) *DisplayVideo360AdvertiserLinkProposalIterator { + return c.internalClient.ListDisplayVideo360AdvertiserLinkProposals(ctx, req, opts...) +} + +// CreateDisplayVideo360AdvertiserLinkProposal creates a DisplayVideo360AdvertiserLinkProposal. +func (c *AnalyticsAdminClient) CreateDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.CreateDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { + return c.internalClient.CreateDisplayVideo360AdvertiserLinkProposal(ctx, req, opts...) +} + +// DeleteDisplayVideo360AdvertiserLinkProposal deletes a DisplayVideo360AdvertiserLinkProposal on a property. +// This can only be used on cancelled proposals. +func (c *AnalyticsAdminClient) DeleteDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.DeleteDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) error { + return c.internalClient.DeleteDisplayVideo360AdvertiserLinkProposal(ctx, req, opts...) +} + +// ApproveDisplayVideo360AdvertiserLinkProposal approves a DisplayVideo360AdvertiserLinkProposal. +// The DisplayVideo360AdvertiserLinkProposal will be deleted and a new +// DisplayVideo360AdvertiserLink will be created. +func (c *AnalyticsAdminClient) ApproveDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.ApproveDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.ApproveDisplayVideo360AdvertiserLinkProposalResponse, error) { + return c.internalClient.ApproveDisplayVideo360AdvertiserLinkProposal(ctx, req, opts...) +} + +// CancelDisplayVideo360AdvertiserLinkProposal cancels a DisplayVideo360AdvertiserLinkProposal. +// Cancelling can mean either: +// +// Declining a proposal initiated from Display & Video 360 +// +// Withdrawing a proposal initiated from Google Analytics +// After being cancelled, a proposal will eventually be deleted automatically. +func (c *AnalyticsAdminClient) CancelDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.CancelDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { + return c.internalClient.CancelDisplayVideo360AdvertiserLinkProposal(ctx, req, opts...) +} + +// CreateCustomDimension creates a CustomDimension. +func (c *AnalyticsAdminClient) CreateCustomDimension(ctx context.Context, req *adminpb.CreateCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { + return c.internalClient.CreateCustomDimension(ctx, req, opts...) +} + +// UpdateCustomDimension updates a CustomDimension on a property. +func (c *AnalyticsAdminClient) UpdateCustomDimension(ctx context.Context, req *adminpb.UpdateCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { + return c.internalClient.UpdateCustomDimension(ctx, req, opts...) +} + +// ListCustomDimensions lists CustomDimensions on a property. +func (c *AnalyticsAdminClient) ListCustomDimensions(ctx context.Context, req *adminpb.ListCustomDimensionsRequest, opts ...gax.CallOption) *CustomDimensionIterator { + return c.internalClient.ListCustomDimensions(ctx, req, opts...) +} + +// ArchiveCustomDimension archives a CustomDimension on a property. +func (c *AnalyticsAdminClient) ArchiveCustomDimension(ctx context.Context, req *adminpb.ArchiveCustomDimensionRequest, opts ...gax.CallOption) error { + return c.internalClient.ArchiveCustomDimension(ctx, req, opts...) +} + +// GetCustomDimension lookup for a single CustomDimension. +func (c *AnalyticsAdminClient) GetCustomDimension(ctx context.Context, req *adminpb.GetCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { + return c.internalClient.GetCustomDimension(ctx, req, opts...) +} + +// CreateCustomMetric creates a CustomMetric. +func (c *AnalyticsAdminClient) CreateCustomMetric(ctx context.Context, req *adminpb.CreateCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { + return c.internalClient.CreateCustomMetric(ctx, req, opts...) +} + +// UpdateCustomMetric updates a CustomMetric on a property. +func (c *AnalyticsAdminClient) UpdateCustomMetric(ctx context.Context, req *adminpb.UpdateCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { + return c.internalClient.UpdateCustomMetric(ctx, req, opts...) +} + +// ListCustomMetrics lists CustomMetrics on a property. +func (c *AnalyticsAdminClient) ListCustomMetrics(ctx context.Context, req *adminpb.ListCustomMetricsRequest, opts ...gax.CallOption) *CustomMetricIterator { + return c.internalClient.ListCustomMetrics(ctx, req, opts...) +} + +// ArchiveCustomMetric archives a CustomMetric on a property. +func (c *AnalyticsAdminClient) ArchiveCustomMetric(ctx context.Context, req *adminpb.ArchiveCustomMetricRequest, opts ...gax.CallOption) error { + return c.internalClient.ArchiveCustomMetric(ctx, req, opts...) +} + +// GetCustomMetric lookup for a single CustomMetric. +func (c *AnalyticsAdminClient) GetCustomMetric(ctx context.Context, req *adminpb.GetCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { + return c.internalClient.GetCustomMetric(ctx, req, opts...) +} + +// GetDataRetentionSettings returns the singleton data retention settings for this property. +func (c *AnalyticsAdminClient) GetDataRetentionSettings(ctx context.Context, req *adminpb.GetDataRetentionSettingsRequest, opts ...gax.CallOption) (*adminpb.DataRetentionSettings, error) { + return c.internalClient.GetDataRetentionSettings(ctx, req, opts...) +} + +// UpdateDataRetentionSettings updates the singleton data retention settings for this property. +func (c *AnalyticsAdminClient) UpdateDataRetentionSettings(ctx context.Context, req *adminpb.UpdateDataRetentionSettingsRequest, opts ...gax.CallOption) (*adminpb.DataRetentionSettings, error) { + return c.internalClient.UpdateDataRetentionSettings(ctx, req, opts...) +} + +// CreateDataStream creates a DataStream. +func (c *AnalyticsAdminClient) CreateDataStream(ctx context.Context, req *adminpb.CreateDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { + return c.internalClient.CreateDataStream(ctx, req, opts...) +} + +// DeleteDataStream deletes a DataStream on a property. +func (c *AnalyticsAdminClient) DeleteDataStream(ctx context.Context, req *adminpb.DeleteDataStreamRequest, opts ...gax.CallOption) error { + return c.internalClient.DeleteDataStream(ctx, req, opts...) +} + +// UpdateDataStream updates a DataStream on a property. +func (c *AnalyticsAdminClient) UpdateDataStream(ctx context.Context, req *adminpb.UpdateDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { + return c.internalClient.UpdateDataStream(ctx, req, opts...) +} + +// ListDataStreams lists DataStreams on a property. +func (c *AnalyticsAdminClient) ListDataStreams(ctx context.Context, req *adminpb.ListDataStreamsRequest, opts ...gax.CallOption) *DataStreamIterator { + return c.internalClient.ListDataStreams(ctx, req, opts...) +} + +// GetDataStream lookup for a single DataStream. +func (c *AnalyticsAdminClient) GetDataStream(ctx context.Context, req *adminpb.GetDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { + return c.internalClient.GetDataStream(ctx, req, opts...) +} + +// analyticsAdminGRPCClient is a client for interacting with Google Analytics Admin API over gRPC transport. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type analyticsAdminGRPCClient struct { + // Connection pool of gRPC connections to the service. + connPool gtransport.ConnPool + + // flag to opt out of default deadlines via GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE + disableDeadlines bool + + // Points back to the CallOptions field of the containing AnalyticsAdminClient + CallOptions **AnalyticsAdminCallOptions + + // The gRPC API client. + analyticsAdminClient adminpb.AnalyticsAdminServiceClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewAnalyticsAdminClient creates a new analytics admin service client based on gRPC. +// The returned client must be Closed when it is done being used to clean up its underlying connections. +// +// Service Interface for the Analytics Admin API (GA4). +func NewAnalyticsAdminClient(ctx context.Context, opts ...option.ClientOption) (*AnalyticsAdminClient, error) { + clientOpts := defaultAnalyticsAdminGRPCClientOptions() + if newAnalyticsAdminClientHook != nil { + hookOpts, err := newAnalyticsAdminClientHook(ctx, clientHookParams{}) + if err != nil { + return nil, err + } + clientOpts = append(clientOpts, hookOpts...) + } + + disableDeadlines, err := checkDisableDeadlines() + if err != nil { + return nil, err + } + + connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...) + if err != nil { + return nil, err + } + client := AnalyticsAdminClient{CallOptions: defaultAnalyticsAdminCallOptions()} + + c := &analyticsAdminGRPCClient{ + connPool: connPool, + disableDeadlines: disableDeadlines, + analyticsAdminClient: adminpb.NewAnalyticsAdminServiceClient(connPool), + CallOptions: &client.CallOptions, + } + c.setGoogleClientInfo() + + client.internalClient = c + + return &client, nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *analyticsAdminGRPCClient) Connection() *grpc.ClientConn { + return c.connPool.Conn() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *analyticsAdminGRPCClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *analyticsAdminGRPCClient) Close() error { + return c.connPool.Close() +} + +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type analyticsAdminRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing AnalyticsAdminClient + CallOptions **AnalyticsAdminCallOptions +} + +// NewAnalyticsAdminRESTClient creates a new analytics admin service rest client. +// +// Service Interface for the Analytics Admin API (GA4). +func NewAnalyticsAdminRESTClient(ctx context.Context, opts ...option.ClientOption) (*AnalyticsAdminClient, error) { + clientOpts := append(defaultAnalyticsAdminRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultAnalyticsAdminRESTCallOptions() + c := &analyticsAdminRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &AnalyticsAdminClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultAnalyticsAdminRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://analyticsadmin.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://analyticsadmin.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://analyticsadmin.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *analyticsAdminRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *analyticsAdminRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *analyticsAdminRESTClient) Connection() *grpc.ClientConn { + return nil +} +func (c *analyticsAdminGRPCClient) GetAccount(ctx context.Context, req *adminpb.GetAccountRequest, opts ...gax.CallOption) (*adminpb.Account, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetAccount[0:len((*c.CallOptions).GetAccount):len((*c.CallOptions).GetAccount)], opts...) + var resp *adminpb.Account + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetAccount(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) ListAccounts(ctx context.Context, req *adminpb.ListAccountsRequest, opts ...gax.CallOption) *AccountIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append((*c.CallOptions).ListAccounts[0:len((*c.CallOptions).ListAccounts):len((*c.CallOptions).ListAccounts)], opts...) + it := &AccountIterator{} + req = proto.Clone(req).(*adminpb.ListAccountsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.Account, string, error) { + resp := &adminpb.ListAccountsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ListAccounts(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetAccounts(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) DeleteAccount(ctx context.Context, req *adminpb.DeleteAccountRequest, opts ...gax.CallOption) error { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteAccount[0:len((*c.CallOptions).DeleteAccount):len((*c.CallOptions).DeleteAccount)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.analyticsAdminClient.DeleteAccount(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *analyticsAdminGRPCClient) UpdateAccount(ctx context.Context, req *adminpb.UpdateAccountRequest, opts ...gax.CallOption) (*adminpb.Account, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "account.name", url.QueryEscape(req.GetAccount().GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateAccount[0:len((*c.CallOptions).UpdateAccount):len((*c.CallOptions).UpdateAccount)], opts...) + var resp *adminpb.Account + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.UpdateAccount(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) ProvisionAccountTicket(ctx context.Context, req *adminpb.ProvisionAccountTicketRequest, opts ...gax.CallOption) (*adminpb.ProvisionAccountTicketResponse, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append((*c.CallOptions).ProvisionAccountTicket[0:len((*c.CallOptions).ProvisionAccountTicket):len((*c.CallOptions).ProvisionAccountTicket)], opts...) + var resp *adminpb.ProvisionAccountTicketResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ProvisionAccountTicket(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) ListAccountSummaries(ctx context.Context, req *adminpb.ListAccountSummariesRequest, opts ...gax.CallOption) *AccountSummaryIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append((*c.CallOptions).ListAccountSummaries[0:len((*c.CallOptions).ListAccountSummaries):len((*c.CallOptions).ListAccountSummaries)], opts...) + it := &AccountSummaryIterator{} + req = proto.Clone(req).(*adminpb.ListAccountSummariesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.AccountSummary, string, error) { + resp := &adminpb.ListAccountSummariesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ListAccountSummaries(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetAccountSummaries(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) GetProperty(ctx context.Context, req *adminpb.GetPropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetProperty[0:len((*c.CallOptions).GetProperty):len((*c.CallOptions).GetProperty)], opts...) + var resp *adminpb.Property + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetProperty(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) ListProperties(ctx context.Context, req *adminpb.ListPropertiesRequest, opts ...gax.CallOption) *PropertyIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append((*c.CallOptions).ListProperties[0:len((*c.CallOptions).ListProperties):len((*c.CallOptions).ListProperties)], opts...) + it := &PropertyIterator{} + req = proto.Clone(req).(*adminpb.ListPropertiesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.Property, string, error) { + resp := &adminpb.ListPropertiesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ListProperties(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetProperties(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) CreateProperty(ctx context.Context, req *adminpb.CreatePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append((*c.CallOptions).CreateProperty[0:len((*c.CallOptions).CreateProperty):len((*c.CallOptions).CreateProperty)], opts...) + var resp *adminpb.Property + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.CreateProperty(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) DeleteProperty(ctx context.Context, req *adminpb.DeletePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteProperty[0:len((*c.CallOptions).DeleteProperty):len((*c.CallOptions).DeleteProperty)], opts...) + var resp *adminpb.Property + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.DeleteProperty(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) UpdateProperty(ctx context.Context, req *adminpb.UpdatePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "property.name", url.QueryEscape(req.GetProperty().GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateProperty[0:len((*c.CallOptions).UpdateProperty):len((*c.CallOptions).UpdateProperty)], opts...) + var resp *adminpb.Property + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.UpdateProperty(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) GetUserLink(ctx context.Context, req *adminpb.GetUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetUserLink[0:len((*c.CallOptions).GetUserLink):len((*c.CallOptions).GetUserLink)], opts...) + var resp *adminpb.UserLink + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetUserLink(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) BatchGetUserLinks(ctx context.Context, req *adminpb.BatchGetUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchGetUserLinksResponse, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).BatchGetUserLinks[0:len((*c.CallOptions).BatchGetUserLinks):len((*c.CallOptions).BatchGetUserLinks)], opts...) + var resp *adminpb.BatchGetUserLinksResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.BatchGetUserLinks(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) ListUserLinks(ctx context.Context, req *adminpb.ListUserLinksRequest, opts ...gax.CallOption) *UserLinkIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListUserLinks[0:len((*c.CallOptions).ListUserLinks):len((*c.CallOptions).ListUserLinks)], opts...) + it := &UserLinkIterator{} + req = proto.Clone(req).(*adminpb.ListUserLinksRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.UserLink, string, error) { + resp := &adminpb.ListUserLinksResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ListUserLinks(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetUserLinks(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) AuditUserLinks(ctx context.Context, req *adminpb.AuditUserLinksRequest, opts ...gax.CallOption) *AuditUserLinkIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).AuditUserLinks[0:len((*c.CallOptions).AuditUserLinks):len((*c.CallOptions).AuditUserLinks)], opts...) + it := &AuditUserLinkIterator{} + req = proto.Clone(req).(*adminpb.AuditUserLinksRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.AuditUserLink, string, error) { + resp := &adminpb.AuditUserLinksResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.AuditUserLinks(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetUserLinks(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) CreateUserLink(ctx context.Context, req *adminpb.CreateUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CreateUserLink[0:len((*c.CallOptions).CreateUserLink):len((*c.CallOptions).CreateUserLink)], opts...) + var resp *adminpb.UserLink + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.CreateUserLink(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) BatchCreateUserLinks(ctx context.Context, req *adminpb.BatchCreateUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchCreateUserLinksResponse, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).BatchCreateUserLinks[0:len((*c.CallOptions).BatchCreateUserLinks):len((*c.CallOptions).BatchCreateUserLinks)], opts...) + var resp *adminpb.BatchCreateUserLinksResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.BatchCreateUserLinks(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) UpdateUserLink(ctx context.Context, req *adminpb.UpdateUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "user_link.name", url.QueryEscape(req.GetUserLink().GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateUserLink[0:len((*c.CallOptions).UpdateUserLink):len((*c.CallOptions).UpdateUserLink)], opts...) + var resp *adminpb.UserLink + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.UpdateUserLink(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) BatchUpdateUserLinks(ctx context.Context, req *adminpb.BatchUpdateUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchUpdateUserLinksResponse, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).BatchUpdateUserLinks[0:len((*c.CallOptions).BatchUpdateUserLinks):len((*c.CallOptions).BatchUpdateUserLinks)], opts...) + var resp *adminpb.BatchUpdateUserLinksResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.BatchUpdateUserLinks(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) DeleteUserLink(ctx context.Context, req *adminpb.DeleteUserLinkRequest, opts ...gax.CallOption) error { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteUserLink[0:len((*c.CallOptions).DeleteUserLink):len((*c.CallOptions).DeleteUserLink)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.analyticsAdminClient.DeleteUserLink(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *analyticsAdminGRPCClient) BatchDeleteUserLinks(ctx context.Context, req *adminpb.BatchDeleteUserLinksRequest, opts ...gax.CallOption) error { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).BatchDeleteUserLinks[0:len((*c.CallOptions).BatchDeleteUserLinks):len((*c.CallOptions).BatchDeleteUserLinks)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.analyticsAdminClient.BatchDeleteUserLinks(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *analyticsAdminGRPCClient) CreateFirebaseLink(ctx context.Context, req *adminpb.CreateFirebaseLinkRequest, opts ...gax.CallOption) (*adminpb.FirebaseLink, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CreateFirebaseLink[0:len((*c.CallOptions).CreateFirebaseLink):len((*c.CallOptions).CreateFirebaseLink)], opts...) + var resp *adminpb.FirebaseLink + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.CreateFirebaseLink(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) DeleteFirebaseLink(ctx context.Context, req *adminpb.DeleteFirebaseLinkRequest, opts ...gax.CallOption) error { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteFirebaseLink[0:len((*c.CallOptions).DeleteFirebaseLink):len((*c.CallOptions).DeleteFirebaseLink)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.analyticsAdminClient.DeleteFirebaseLink(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *analyticsAdminGRPCClient) ListFirebaseLinks(ctx context.Context, req *adminpb.ListFirebaseLinksRequest, opts ...gax.CallOption) *FirebaseLinkIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListFirebaseLinks[0:len((*c.CallOptions).ListFirebaseLinks):len((*c.CallOptions).ListFirebaseLinks)], opts...) + it := &FirebaseLinkIterator{} + req = proto.Clone(req).(*adminpb.ListFirebaseLinksRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.FirebaseLink, string, error) { + resp := &adminpb.ListFirebaseLinksResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ListFirebaseLinks(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetFirebaseLinks(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) GetGlobalSiteTag(ctx context.Context, req *adminpb.GetGlobalSiteTagRequest, opts ...gax.CallOption) (*adminpb.GlobalSiteTag, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetGlobalSiteTag[0:len((*c.CallOptions).GetGlobalSiteTag):len((*c.CallOptions).GetGlobalSiteTag)], opts...) + var resp *adminpb.GlobalSiteTag + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetGlobalSiteTag(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) CreateGoogleAdsLink(ctx context.Context, req *adminpb.CreateGoogleAdsLinkRequest, opts ...gax.CallOption) (*adminpb.GoogleAdsLink, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CreateGoogleAdsLink[0:len((*c.CallOptions).CreateGoogleAdsLink):len((*c.CallOptions).CreateGoogleAdsLink)], opts...) + var resp *adminpb.GoogleAdsLink + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.CreateGoogleAdsLink(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) UpdateGoogleAdsLink(ctx context.Context, req *adminpb.UpdateGoogleAdsLinkRequest, opts ...gax.CallOption) (*adminpb.GoogleAdsLink, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "google_ads_link.name", url.QueryEscape(req.GetGoogleAdsLink().GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateGoogleAdsLink[0:len((*c.CallOptions).UpdateGoogleAdsLink):len((*c.CallOptions).UpdateGoogleAdsLink)], opts...) + var resp *adminpb.GoogleAdsLink + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.UpdateGoogleAdsLink(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) DeleteGoogleAdsLink(ctx context.Context, req *adminpb.DeleteGoogleAdsLinkRequest, opts ...gax.CallOption) error { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteGoogleAdsLink[0:len((*c.CallOptions).DeleteGoogleAdsLink):len((*c.CallOptions).DeleteGoogleAdsLink)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.analyticsAdminClient.DeleteGoogleAdsLink(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *analyticsAdminGRPCClient) ListGoogleAdsLinks(ctx context.Context, req *adminpb.ListGoogleAdsLinksRequest, opts ...gax.CallOption) *GoogleAdsLinkIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListGoogleAdsLinks[0:len((*c.CallOptions).ListGoogleAdsLinks):len((*c.CallOptions).ListGoogleAdsLinks)], opts...) + it := &GoogleAdsLinkIterator{} + req = proto.Clone(req).(*adminpb.ListGoogleAdsLinksRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.GoogleAdsLink, string, error) { + resp := &adminpb.ListGoogleAdsLinksResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ListGoogleAdsLinks(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetGoogleAdsLinks(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) GetDataSharingSettings(ctx context.Context, req *adminpb.GetDataSharingSettingsRequest, opts ...gax.CallOption) (*adminpb.DataSharingSettings, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetDataSharingSettings[0:len((*c.CallOptions).GetDataSharingSettings):len((*c.CallOptions).GetDataSharingSettings)], opts...) + var resp *adminpb.DataSharingSettings + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetDataSharingSettings(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) GetMeasurementProtocolSecret(ctx context.Context, req *adminpb.GetMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetMeasurementProtocolSecret[0:len((*c.CallOptions).GetMeasurementProtocolSecret):len((*c.CallOptions).GetMeasurementProtocolSecret)], opts...) + var resp *adminpb.MeasurementProtocolSecret + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetMeasurementProtocolSecret(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) ListMeasurementProtocolSecrets(ctx context.Context, req *adminpb.ListMeasurementProtocolSecretsRequest, opts ...gax.CallOption) *MeasurementProtocolSecretIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListMeasurementProtocolSecrets[0:len((*c.CallOptions).ListMeasurementProtocolSecrets):len((*c.CallOptions).ListMeasurementProtocolSecrets)], opts...) + it := &MeasurementProtocolSecretIterator{} + req = proto.Clone(req).(*adminpb.ListMeasurementProtocolSecretsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.MeasurementProtocolSecret, string, error) { + resp := &adminpb.ListMeasurementProtocolSecretsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ListMeasurementProtocolSecrets(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetMeasurementProtocolSecrets(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) CreateMeasurementProtocolSecret(ctx context.Context, req *adminpb.CreateMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CreateMeasurementProtocolSecret[0:len((*c.CallOptions).CreateMeasurementProtocolSecret):len((*c.CallOptions).CreateMeasurementProtocolSecret)], opts...) + var resp *adminpb.MeasurementProtocolSecret + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.CreateMeasurementProtocolSecret(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) DeleteMeasurementProtocolSecret(ctx context.Context, req *adminpb.DeleteMeasurementProtocolSecretRequest, opts ...gax.CallOption) error { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteMeasurementProtocolSecret[0:len((*c.CallOptions).DeleteMeasurementProtocolSecret):len((*c.CallOptions).DeleteMeasurementProtocolSecret)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.analyticsAdminClient.DeleteMeasurementProtocolSecret(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *analyticsAdminGRPCClient) UpdateMeasurementProtocolSecret(ctx context.Context, req *adminpb.UpdateMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "measurement_protocol_secret.name", url.QueryEscape(req.GetMeasurementProtocolSecret().GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateMeasurementProtocolSecret[0:len((*c.CallOptions).UpdateMeasurementProtocolSecret):len((*c.CallOptions).UpdateMeasurementProtocolSecret)], opts...) + var resp *adminpb.MeasurementProtocolSecret + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.UpdateMeasurementProtocolSecret(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) AcknowledgeUserDataCollection(ctx context.Context, req *adminpb.AcknowledgeUserDataCollectionRequest, opts ...gax.CallOption) (*adminpb.AcknowledgeUserDataCollectionResponse, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "property", url.QueryEscape(req.GetProperty()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).AcknowledgeUserDataCollection[0:len((*c.CallOptions).AcknowledgeUserDataCollection):len((*c.CallOptions).AcknowledgeUserDataCollection)], opts...) + var resp *adminpb.AcknowledgeUserDataCollectionResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.AcknowledgeUserDataCollection(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) SearchChangeHistoryEvents(ctx context.Context, req *adminpb.SearchChangeHistoryEventsRequest, opts ...gax.CallOption) *ChangeHistoryEventIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "account", url.QueryEscape(req.GetAccount()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).SearchChangeHistoryEvents[0:len((*c.CallOptions).SearchChangeHistoryEvents):len((*c.CallOptions).SearchChangeHistoryEvents)], opts...) + it := &ChangeHistoryEventIterator{} + req = proto.Clone(req).(*adminpb.SearchChangeHistoryEventsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.ChangeHistoryEvent, string, error) { + resp := &adminpb.SearchChangeHistoryEventsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.SearchChangeHistoryEvents(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetChangeHistoryEvents(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) GetGoogleSignalsSettings(ctx context.Context, req *adminpb.GetGoogleSignalsSettingsRequest, opts ...gax.CallOption) (*adminpb.GoogleSignalsSettings, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetGoogleSignalsSettings[0:len((*c.CallOptions).GetGoogleSignalsSettings):len((*c.CallOptions).GetGoogleSignalsSettings)], opts...) + var resp *adminpb.GoogleSignalsSettings + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetGoogleSignalsSettings(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) UpdateGoogleSignalsSettings(ctx context.Context, req *adminpb.UpdateGoogleSignalsSettingsRequest, opts ...gax.CallOption) (*adminpb.GoogleSignalsSettings, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "google_signals_settings.name", url.QueryEscape(req.GetGoogleSignalsSettings().GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateGoogleSignalsSettings[0:len((*c.CallOptions).UpdateGoogleSignalsSettings):len((*c.CallOptions).UpdateGoogleSignalsSettings)], opts...) + var resp *adminpb.GoogleSignalsSettings + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.UpdateGoogleSignalsSettings(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) CreateConversionEvent(ctx context.Context, req *adminpb.CreateConversionEventRequest, opts ...gax.CallOption) (*adminpb.ConversionEvent, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CreateConversionEvent[0:len((*c.CallOptions).CreateConversionEvent):len((*c.CallOptions).CreateConversionEvent)], opts...) + var resp *adminpb.ConversionEvent + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.CreateConversionEvent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) GetConversionEvent(ctx context.Context, req *adminpb.GetConversionEventRequest, opts ...gax.CallOption) (*adminpb.ConversionEvent, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetConversionEvent[0:len((*c.CallOptions).GetConversionEvent):len((*c.CallOptions).GetConversionEvent)], opts...) + var resp *adminpb.ConversionEvent + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetConversionEvent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) DeleteConversionEvent(ctx context.Context, req *adminpb.DeleteConversionEventRequest, opts ...gax.CallOption) error { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteConversionEvent[0:len((*c.CallOptions).DeleteConversionEvent):len((*c.CallOptions).DeleteConversionEvent)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.analyticsAdminClient.DeleteConversionEvent(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *analyticsAdminGRPCClient) ListConversionEvents(ctx context.Context, req *adminpb.ListConversionEventsRequest, opts ...gax.CallOption) *ConversionEventIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListConversionEvents[0:len((*c.CallOptions).ListConversionEvents):len((*c.CallOptions).ListConversionEvents)], opts...) + it := &ConversionEventIterator{} + req = proto.Clone(req).(*adminpb.ListConversionEventsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.ConversionEvent, string, error) { + resp := &adminpb.ListConversionEventsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ListConversionEvents(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetConversionEvents(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) GetDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.GetDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetDisplayVideo360AdvertiserLink[0:len((*c.CallOptions).GetDisplayVideo360AdvertiserLink):len((*c.CallOptions).GetDisplayVideo360AdvertiserLink)], opts...) + var resp *adminpb.DisplayVideo360AdvertiserLink + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetDisplayVideo360AdvertiserLink(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) ListDisplayVideo360AdvertiserLinks(ctx context.Context, req *adminpb.ListDisplayVideo360AdvertiserLinksRequest, opts ...gax.CallOption) *DisplayVideo360AdvertiserLinkIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListDisplayVideo360AdvertiserLinks[0:len((*c.CallOptions).ListDisplayVideo360AdvertiserLinks):len((*c.CallOptions).ListDisplayVideo360AdvertiserLinks)], opts...) + it := &DisplayVideo360AdvertiserLinkIterator{} + req = proto.Clone(req).(*adminpb.ListDisplayVideo360AdvertiserLinksRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.DisplayVideo360AdvertiserLink, string, error) { + resp := &adminpb.ListDisplayVideo360AdvertiserLinksResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ListDisplayVideo360AdvertiserLinks(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetDisplayVideo_360AdvertiserLinks(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) CreateDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.CreateDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CreateDisplayVideo360AdvertiserLink[0:len((*c.CallOptions).CreateDisplayVideo360AdvertiserLink):len((*c.CallOptions).CreateDisplayVideo360AdvertiserLink)], opts...) + var resp *adminpb.DisplayVideo360AdvertiserLink + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.CreateDisplayVideo360AdvertiserLink(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) DeleteDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.DeleteDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) error { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteDisplayVideo360AdvertiserLink[0:len((*c.CallOptions).DeleteDisplayVideo360AdvertiserLink):len((*c.CallOptions).DeleteDisplayVideo360AdvertiserLink)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.analyticsAdminClient.DeleteDisplayVideo360AdvertiserLink(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *analyticsAdminGRPCClient) UpdateDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.UpdateDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "display_video_360_advertiser_link.name", url.QueryEscape(req.GetDisplayVideo_360AdvertiserLink().GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateDisplayVideo360AdvertiserLink[0:len((*c.CallOptions).UpdateDisplayVideo360AdvertiserLink):len((*c.CallOptions).UpdateDisplayVideo360AdvertiserLink)], opts...) + var resp *adminpb.DisplayVideo360AdvertiserLink + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.UpdateDisplayVideo360AdvertiserLink(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) GetDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.GetDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetDisplayVideo360AdvertiserLinkProposal[0:len((*c.CallOptions).GetDisplayVideo360AdvertiserLinkProposal):len((*c.CallOptions).GetDisplayVideo360AdvertiserLinkProposal)], opts...) + var resp *adminpb.DisplayVideo360AdvertiserLinkProposal + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetDisplayVideo360AdvertiserLinkProposal(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) ListDisplayVideo360AdvertiserLinkProposals(ctx context.Context, req *adminpb.ListDisplayVideo360AdvertiserLinkProposalsRequest, opts ...gax.CallOption) *DisplayVideo360AdvertiserLinkProposalIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListDisplayVideo360AdvertiserLinkProposals[0:len((*c.CallOptions).ListDisplayVideo360AdvertiserLinkProposals):len((*c.CallOptions).ListDisplayVideo360AdvertiserLinkProposals)], opts...) + it := &DisplayVideo360AdvertiserLinkProposalIterator{} + req = proto.Clone(req).(*adminpb.ListDisplayVideo360AdvertiserLinkProposalsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.DisplayVideo360AdvertiserLinkProposal, string, error) { + resp := &adminpb.ListDisplayVideo360AdvertiserLinkProposalsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ListDisplayVideo360AdvertiserLinkProposals(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetDisplayVideo_360AdvertiserLinkProposals(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) CreateDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.CreateDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CreateDisplayVideo360AdvertiserLinkProposal[0:len((*c.CallOptions).CreateDisplayVideo360AdvertiserLinkProposal):len((*c.CallOptions).CreateDisplayVideo360AdvertiserLinkProposal)], opts...) + var resp *adminpb.DisplayVideo360AdvertiserLinkProposal + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.CreateDisplayVideo360AdvertiserLinkProposal(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) DeleteDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.DeleteDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) error { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteDisplayVideo360AdvertiserLinkProposal[0:len((*c.CallOptions).DeleteDisplayVideo360AdvertiserLinkProposal):len((*c.CallOptions).DeleteDisplayVideo360AdvertiserLinkProposal)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.analyticsAdminClient.DeleteDisplayVideo360AdvertiserLinkProposal(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *analyticsAdminGRPCClient) ApproveDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.ApproveDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.ApproveDisplayVideo360AdvertiserLinkProposalResponse, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ApproveDisplayVideo360AdvertiserLinkProposal[0:len((*c.CallOptions).ApproveDisplayVideo360AdvertiserLinkProposal):len((*c.CallOptions).ApproveDisplayVideo360AdvertiserLinkProposal)], opts...) + var resp *adminpb.ApproveDisplayVideo360AdvertiserLinkProposalResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ApproveDisplayVideo360AdvertiserLinkProposal(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) CancelDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.CancelDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CancelDisplayVideo360AdvertiserLinkProposal[0:len((*c.CallOptions).CancelDisplayVideo360AdvertiserLinkProposal):len((*c.CallOptions).CancelDisplayVideo360AdvertiserLinkProposal)], opts...) + var resp *adminpb.DisplayVideo360AdvertiserLinkProposal + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.CancelDisplayVideo360AdvertiserLinkProposal(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) CreateCustomDimension(ctx context.Context, req *adminpb.CreateCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CreateCustomDimension[0:len((*c.CallOptions).CreateCustomDimension):len((*c.CallOptions).CreateCustomDimension)], opts...) + var resp *adminpb.CustomDimension + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.CreateCustomDimension(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) UpdateCustomDimension(ctx context.Context, req *adminpb.UpdateCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "custom_dimension.name", url.QueryEscape(req.GetCustomDimension().GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateCustomDimension[0:len((*c.CallOptions).UpdateCustomDimension):len((*c.CallOptions).UpdateCustomDimension)], opts...) + var resp *adminpb.CustomDimension + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.UpdateCustomDimension(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) ListCustomDimensions(ctx context.Context, req *adminpb.ListCustomDimensionsRequest, opts ...gax.CallOption) *CustomDimensionIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListCustomDimensions[0:len((*c.CallOptions).ListCustomDimensions):len((*c.CallOptions).ListCustomDimensions)], opts...) + it := &CustomDimensionIterator{} + req = proto.Clone(req).(*adminpb.ListCustomDimensionsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.CustomDimension, string, error) { + resp := &adminpb.ListCustomDimensionsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ListCustomDimensions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetCustomDimensions(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) ArchiveCustomDimension(ctx context.Context, req *adminpb.ArchiveCustomDimensionRequest, opts ...gax.CallOption) error { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ArchiveCustomDimension[0:len((*c.CallOptions).ArchiveCustomDimension):len((*c.CallOptions).ArchiveCustomDimension)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.analyticsAdminClient.ArchiveCustomDimension(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *analyticsAdminGRPCClient) GetCustomDimension(ctx context.Context, req *adminpb.GetCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetCustomDimension[0:len((*c.CallOptions).GetCustomDimension):len((*c.CallOptions).GetCustomDimension)], opts...) + var resp *adminpb.CustomDimension + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetCustomDimension(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) CreateCustomMetric(ctx context.Context, req *adminpb.CreateCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CreateCustomMetric[0:len((*c.CallOptions).CreateCustomMetric):len((*c.CallOptions).CreateCustomMetric)], opts...) + var resp *adminpb.CustomMetric + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.CreateCustomMetric(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) UpdateCustomMetric(ctx context.Context, req *adminpb.UpdateCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "custom_metric.name", url.QueryEscape(req.GetCustomMetric().GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateCustomMetric[0:len((*c.CallOptions).UpdateCustomMetric):len((*c.CallOptions).UpdateCustomMetric)], opts...) + var resp *adminpb.CustomMetric + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.UpdateCustomMetric(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) ListCustomMetrics(ctx context.Context, req *adminpb.ListCustomMetricsRequest, opts ...gax.CallOption) *CustomMetricIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListCustomMetrics[0:len((*c.CallOptions).ListCustomMetrics):len((*c.CallOptions).ListCustomMetrics)], opts...) + it := &CustomMetricIterator{} + req = proto.Clone(req).(*adminpb.ListCustomMetricsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.CustomMetric, string, error) { + resp := &adminpb.ListCustomMetricsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ListCustomMetrics(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetCustomMetrics(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *analyticsAdminGRPCClient) ArchiveCustomMetric(ctx context.Context, req *adminpb.ArchiveCustomMetricRequest, opts ...gax.CallOption) error { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ArchiveCustomMetric[0:len((*c.CallOptions).ArchiveCustomMetric):len((*c.CallOptions).ArchiveCustomMetric)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.analyticsAdminClient.ArchiveCustomMetric(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *analyticsAdminGRPCClient) GetCustomMetric(ctx context.Context, req *adminpb.GetCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetCustomMetric[0:len((*c.CallOptions).GetCustomMetric):len((*c.CallOptions).GetCustomMetric)], opts...) + var resp *adminpb.CustomMetric + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetCustomMetric(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) GetDataRetentionSettings(ctx context.Context, req *adminpb.GetDataRetentionSettingsRequest, opts ...gax.CallOption) (*adminpb.DataRetentionSettings, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetDataRetentionSettings[0:len((*c.CallOptions).GetDataRetentionSettings):len((*c.CallOptions).GetDataRetentionSettings)], opts...) + var resp *adminpb.DataRetentionSettings + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetDataRetentionSettings(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) UpdateDataRetentionSettings(ctx context.Context, req *adminpb.UpdateDataRetentionSettingsRequest, opts ...gax.CallOption) (*adminpb.DataRetentionSettings, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "data_retention_settings.name", url.QueryEscape(req.GetDataRetentionSettings().GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateDataRetentionSettings[0:len((*c.CallOptions).UpdateDataRetentionSettings):len((*c.CallOptions).UpdateDataRetentionSettings)], opts...) + var resp *adminpb.DataRetentionSettings + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.UpdateDataRetentionSettings(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) CreateDataStream(ctx context.Context, req *adminpb.CreateDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CreateDataStream[0:len((*c.CallOptions).CreateDataStream):len((*c.CallOptions).CreateDataStream)], opts...) + var resp *adminpb.DataStream + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.CreateDataStream(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) DeleteDataStream(ctx context.Context, req *adminpb.DeleteDataStreamRequest, opts ...gax.CallOption) error { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteDataStream[0:len((*c.CallOptions).DeleteDataStream):len((*c.CallOptions).DeleteDataStream)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.analyticsAdminClient.DeleteDataStream(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *analyticsAdminGRPCClient) UpdateDataStream(ctx context.Context, req *adminpb.UpdateDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "data_stream.name", url.QueryEscape(req.GetDataStream().GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateDataStream[0:len((*c.CallOptions).UpdateDataStream):len((*c.CallOptions).UpdateDataStream)], opts...) + var resp *adminpb.DataStream + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.UpdateDataStream(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *analyticsAdminGRPCClient) ListDataStreams(ctx context.Context, req *adminpb.ListDataStreamsRequest, opts ...gax.CallOption) *DataStreamIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - // The call options for this service. - CallOptions *AnalyticsAdminCallOptions -} + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListDataStreams[0:len((*c.CallOptions).ListDataStreams):len((*c.CallOptions).ListDataStreams)], opts...) + it := &DataStreamIterator{} + req = proto.Clone(req).(*adminpb.ListDataStreamsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.DataStream, string, error) { + resp := &adminpb.ListDataStreamsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.ListDataStreams(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } -// Wrapper methods routed to the internal client. + it.Response = resp + return resp.GetDataStreams(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } -// Close closes the connection to the API service. The user should invoke this when -// the client is no longer required. -func (c *AnalyticsAdminClient) Close() error { - return c.internalClient.Close() -} + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() -// setGoogleClientInfo sets the name and version of the application in -// the `x-goog-api-client` header passed on each request. Intended for -// use by Google-written clients. -func (c *AnalyticsAdminClient) setGoogleClientInfo(keyval ...string) { - c.internalClient.setGoogleClientInfo(keyval...) + return it } -// Connection returns a connection to the API service. -// -// Deprecated. -func (c *AnalyticsAdminClient) Connection() *grpc.ClientConn { - return c.internalClient.Connection() +func (c *analyticsAdminGRPCClient) GetDataStream(ctx context.Context, req *adminpb.GetDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { + if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { + cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) + defer cancel() + ctx = cctx + } + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetDataStream[0:len((*c.CallOptions).GetDataStream):len((*c.CallOptions).GetDataStream)], opts...) + var resp *adminpb.DataStream + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.analyticsAdminClient.GetDataStream(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil } // GetAccount lookup for a single Account. -func (c *AnalyticsAdminClient) GetAccount(ctx context.Context, req *adminpb.GetAccountRequest, opts ...gax.CallOption) (*adminpb.Account, error) { - return c.internalClient.GetAccount(ctx, req, opts...) +func (c *analyticsAdminRESTClient) GetAccount(ctx context.Context, req *adminpb.GetAccountRequest, opts ...gax.CallOption) (*adminpb.Account, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetAccount[0:len((*c.CallOptions).GetAccount):len((*c.CallOptions).GetAccount)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.Account{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil } // ListAccounts returns all accounts accessible by the caller. @@ -1103,8 +4364,93 @@ func (c *AnalyticsAdminClient) GetAccount(ctx context.Context, req *adminpb.GetA // Note that these accounts might not currently have GA4 properties. // Soft-deleted (ie: “trashed”) accounts are excluded by default. // Returns an empty list if no relevant accounts are found. -func (c *AnalyticsAdminClient) ListAccounts(ctx context.Context, req *adminpb.ListAccountsRequest, opts ...gax.CallOption) *AccountIterator { - return c.internalClient.ListAccounts(ctx, req, opts...) +func (c *analyticsAdminRESTClient) ListAccounts(ctx context.Context, req *adminpb.ListAccountsRequest, opts ...gax.CallOption) *AccountIterator { + it := &AccountIterator{} + req = proto.Clone(req).(*adminpb.ListAccountsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.Account, string, error) { + resp := &adminpb.ListAccountsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/accounts") + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetShowDeleted() { + params.Add("showDeleted", fmt.Sprintf("%v", req.GetShowDeleted())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetAccounts(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it } // DeleteAccount marks target Account as soft-deleted (ie: “trashed”) and returns it. @@ -1118,514 +4464,708 @@ func (c *AnalyticsAdminClient) ListAccounts(ctx context.Context, req *adminpb.Li // https://support.google.com/analytics/answer/6154772 (at https://support.google.com/analytics/answer/6154772) // // Returns an error if the target is not found. -func (c *AnalyticsAdminClient) DeleteAccount(ctx context.Context, req *adminpb.DeleteAccountRequest, opts ...gax.CallOption) error { - return c.internalClient.DeleteAccount(ctx, req, opts...) -} - -// UpdateAccount updates an account. -func (c *AnalyticsAdminClient) UpdateAccount(ctx context.Context, req *adminpb.UpdateAccountRequest, opts ...gax.CallOption) (*adminpb.Account, error) { - return c.internalClient.UpdateAccount(ctx, req, opts...) -} - -// ProvisionAccountTicket requests a ticket for creating an account. -func (c *AnalyticsAdminClient) ProvisionAccountTicket(ctx context.Context, req *adminpb.ProvisionAccountTicketRequest, opts ...gax.CallOption) (*adminpb.ProvisionAccountTicketResponse, error) { - return c.internalClient.ProvisionAccountTicket(ctx, req, opts...) -} - -// ListAccountSummaries returns summaries of all accounts accessible by the caller. -func (c *AnalyticsAdminClient) ListAccountSummaries(ctx context.Context, req *adminpb.ListAccountSummariesRequest, opts ...gax.CallOption) *AccountSummaryIterator { - return c.internalClient.ListAccountSummaries(ctx, req, opts...) -} - -// GetProperty lookup for a single “GA4” Property. -func (c *AnalyticsAdminClient) GetProperty(ctx context.Context, req *adminpb.GetPropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { - return c.internalClient.GetProperty(ctx, req, opts...) -} - -// ListProperties returns child Properties under the specified parent Account. -// -// Only “GA4” properties will be returned. -// Properties will be excluded if the caller does not have access. -// Soft-deleted (ie: “trashed”) properties are excluded by default. -// Returns an empty list if no relevant properties are found. -func (c *AnalyticsAdminClient) ListProperties(ctx context.Context, req *adminpb.ListPropertiesRequest, opts ...gax.CallOption) *PropertyIterator { - return c.internalClient.ListProperties(ctx, req, opts...) -} +func (c *analyticsAdminRESTClient) DeleteAccount(ctx context.Context, req *adminpb.DeleteAccountRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) -// CreateProperty creates an “GA4” property with the specified location and attributes. -func (c *AnalyticsAdminClient) CreateProperty(ctx context.Context, req *adminpb.CreatePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { - return c.internalClient.CreateProperty(ctx, req, opts...) -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) -// DeleteProperty marks target Property as soft-deleted (ie: “trashed”) and returns it. -// -// This API does not have a method to restore soft-deleted properties. -// However, they can be restored using the Trash Can UI. -// -// If the properties are not restored before the expiration time, the Property -// and all child resources (eg: GoogleAdsLinks, Streams, UserLinks) -// will be permanently purged. -// https://support.google.com/analytics/answer/6154772 (at https://support.google.com/analytics/answer/6154772) -// -// Returns an error if the target is not found, or is not an GA4 Property. -func (c *AnalyticsAdminClient) DeleteProperty(ctx context.Context, req *adminpb.DeletePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { - return c.internalClient.DeleteProperty(ctx, req, opts...) -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// UpdateProperty updates a property. -func (c *AnalyticsAdminClient) UpdateProperty(ctx context.Context, req *adminpb.UpdatePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { - return c.internalClient.UpdateProperty(ctx, req, opts...) -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// GetUserLink gets information about a user’s link to an account or property. -func (c *AnalyticsAdminClient) GetUserLink(ctx context.Context, req *adminpb.GetUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { - return c.internalClient.GetUserLink(ctx, req, opts...) + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) } -// BatchGetUserLinks gets information about multiple users’ links to an account or property. -func (c *AnalyticsAdminClient) BatchGetUserLinks(ctx context.Context, req *adminpb.BatchGetUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchGetUserLinksResponse, error) { - return c.internalClient.BatchGetUserLinks(ctx, req, opts...) -} +// UpdateAccount updates an account. +func (c *analyticsAdminRESTClient) UpdateAccount(ctx context.Context, req *adminpb.UpdateAccountRequest, opts ...gax.CallOption) (*adminpb.Account, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetAccount() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } -// ListUserLinks lists all user links on an account or property. -func (c *AnalyticsAdminClient) ListUserLinks(ctx context.Context, req *adminpb.ListUserLinksRequest, opts ...gax.CallOption) *UserLinkIterator { - return c.internalClient.ListUserLinks(ctx, req, opts...) -} + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetAccount().GetName()) -// AuditUserLinks lists all user links on an account or property, including implicit ones -// that come from effective permissions granted by groups or organization -// admin roles. -// -// If a returned user link does not have direct permissions, they cannot -// be removed from the account or property directly with the DeleteUserLink -// command. They have to be removed from the group/etc that gives them -// permissions, which is currently only usable/discoverable in the GA or GMP -// UIs. -func (c *AnalyticsAdminClient) AuditUserLinks(ctx context.Context, req *adminpb.AuditUserLinksRequest, opts ...gax.CallOption) *AuditUserLinkIterator { - return c.internalClient.AuditUserLinks(ctx, req, opts...) -} + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } -// CreateUserLink creates a user link on an account or property. -// -// If the user with the specified email already has permissions on the -// account or property, then the user’s existing permissions will be unioned -// with the permissions specified in the new UserLink. -func (c *AnalyticsAdminClient) CreateUserLink(ctx context.Context, req *adminpb.CreateUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { - return c.internalClient.CreateUserLink(ctx, req, opts...) -} + baseUrl.RawQuery = params.Encode() -// BatchCreateUserLinks creates information about multiple users’ links to an account or property. -// -// This method is transactional. If any UserLink cannot be created, none of -// the UserLinks will be created. -func (c *AnalyticsAdminClient) BatchCreateUserLinks(ctx context.Context, req *adminpb.BatchCreateUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchCreateUserLinksResponse, error) { - return c.internalClient.BatchCreateUserLinks(ctx, req, opts...) -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "account.name", url.QueryEscape(req.GetAccount().GetName()))) -// UpdateUserLink updates a user link on an account or property. -func (c *AnalyticsAdminClient) UpdateUserLink(ctx context.Context, req *adminpb.UpdateUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { - return c.internalClient.UpdateUserLink(ctx, req, opts...) -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateAccount[0:len((*c.CallOptions).UpdateAccount):len((*c.CallOptions).UpdateAccount)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.Account{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// BatchUpdateUserLinks updates information about multiple users’ links to an account or property. -func (c *AnalyticsAdminClient) BatchUpdateUserLinks(ctx context.Context, req *adminpb.BatchUpdateUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchUpdateUserLinksResponse, error) { - return c.internalClient.BatchUpdateUserLinks(ctx, req, opts...) -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// DeleteUserLink deletes a user link on an account or property. -func (c *AnalyticsAdminClient) DeleteUserLink(ctx context.Context, req *adminpb.DeleteUserLinkRequest, opts ...gax.CallOption) error { - return c.internalClient.DeleteUserLink(ctx, req, opts...) -} + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } -// BatchDeleteUserLinks deletes information about multiple users’ links to an account or property. -func (c *AnalyticsAdminClient) BatchDeleteUserLinks(ctx context.Context, req *adminpb.BatchDeleteUserLinksRequest, opts ...gax.CallOption) error { - return c.internalClient.BatchDeleteUserLinks(ctx, req, opts...) -} + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } -// CreateFirebaseLink creates a FirebaseLink. -// -// Properties can have at most one FirebaseLink. -func (c *AnalyticsAdminClient) CreateFirebaseLink(ctx context.Context, req *adminpb.CreateFirebaseLinkRequest, opts ...gax.CallOption) (*adminpb.FirebaseLink, error) { - return c.internalClient.CreateFirebaseLink(ctx, req, opts...) -} + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } -// DeleteFirebaseLink deletes a FirebaseLink on a property -func (c *AnalyticsAdminClient) DeleteFirebaseLink(ctx context.Context, req *adminpb.DeleteFirebaseLinkRequest, opts ...gax.CallOption) error { - return c.internalClient.DeleteFirebaseLink(ctx, req, opts...) + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil } -// ListFirebaseLinks lists FirebaseLinks on a property. -// Properties can have at most one FirebaseLink. -func (c *AnalyticsAdminClient) ListFirebaseLinks(ctx context.Context, req *adminpb.ListFirebaseLinksRequest, opts ...gax.CallOption) *FirebaseLinkIterator { - return c.internalClient.ListFirebaseLinks(ctx, req, opts...) -} +// ProvisionAccountTicket requests a ticket for creating an account. +func (c *analyticsAdminRESTClient) ProvisionAccountTicket(ctx context.Context, req *adminpb.ProvisionAccountTicketRequest, opts ...gax.CallOption) (*adminpb.ProvisionAccountTicketResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } -// GetGlobalSiteTag returns the Site Tag for the specified web stream. -// Site Tags are immutable singletons. -func (c *AnalyticsAdminClient) GetGlobalSiteTag(ctx context.Context, req *adminpb.GetGlobalSiteTagRequest, opts ...gax.CallOption) (*adminpb.GlobalSiteTag, error) { - return c.internalClient.GetGlobalSiteTag(ctx, req, opts...) -} + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/accounts:provisionAccountTicket") -// CreateGoogleAdsLink creates a GoogleAdsLink. -func (c *AnalyticsAdminClient) CreateGoogleAdsLink(ctx context.Context, req *adminpb.CreateGoogleAdsLinkRequest, opts ...gax.CallOption) (*adminpb.GoogleAdsLink, error) { - return c.internalClient.CreateGoogleAdsLink(ctx, req, opts...) -} + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ProvisionAccountTicket[0:len((*c.CallOptions).ProvisionAccountTicket):len((*c.CallOptions).ProvisionAccountTicket)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.ProvisionAccountTicketResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// UpdateGoogleAdsLink updates a GoogleAdsLink on a property -func (c *AnalyticsAdminClient) UpdateGoogleAdsLink(ctx context.Context, req *adminpb.UpdateGoogleAdsLinkRequest, opts ...gax.CallOption) (*adminpb.GoogleAdsLink, error) { - return c.internalClient.UpdateGoogleAdsLink(ctx, req, opts...) -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// DeleteGoogleAdsLink deletes a GoogleAdsLink on a property -func (c *AnalyticsAdminClient) DeleteGoogleAdsLink(ctx context.Context, req *adminpb.DeleteGoogleAdsLinkRequest, opts ...gax.CallOption) error { - return c.internalClient.DeleteGoogleAdsLink(ctx, req, opts...) -} + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } -// ListGoogleAdsLinks lists GoogleAdsLinks on a property. -func (c *AnalyticsAdminClient) ListGoogleAdsLinks(ctx context.Context, req *adminpb.ListGoogleAdsLinksRequest, opts ...gax.CallOption) *GoogleAdsLinkIterator { - return c.internalClient.ListGoogleAdsLinks(ctx, req, opts...) -} + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } -// GetDataSharingSettings get data sharing settings on an account. -// Data sharing settings are singletons. -func (c *AnalyticsAdminClient) GetDataSharingSettings(ctx context.Context, req *adminpb.GetDataSharingSettingsRequest, opts ...gax.CallOption) (*adminpb.DataSharingSettings, error) { - return c.internalClient.GetDataSharingSettings(ctx, req, opts...) -} + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } -// GetMeasurementProtocolSecret lookup for a single “GA4” MeasurementProtocolSecret. -func (c *AnalyticsAdminClient) GetMeasurementProtocolSecret(ctx context.Context, req *adminpb.GetMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { - return c.internalClient.GetMeasurementProtocolSecret(ctx, req, opts...) + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil } -// ListMeasurementProtocolSecrets returns child MeasurementProtocolSecrets under the specified parent -// Property. -func (c *AnalyticsAdminClient) ListMeasurementProtocolSecrets(ctx context.Context, req *adminpb.ListMeasurementProtocolSecretsRequest, opts ...gax.CallOption) *MeasurementProtocolSecretIterator { - return c.internalClient.ListMeasurementProtocolSecrets(ctx, req, opts...) -} +// ListAccountSummaries returns summaries of all accounts accessible by the caller. +func (c *analyticsAdminRESTClient) ListAccountSummaries(ctx context.Context, req *adminpb.ListAccountSummariesRequest, opts ...gax.CallOption) *AccountSummaryIterator { + it := &AccountSummaryIterator{} + req = proto.Clone(req).(*adminpb.ListAccountSummariesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.AccountSummary, string, error) { + resp := &adminpb.ListAccountSummariesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/accountSummaries") -// CreateMeasurementProtocolSecret creates a measurement protocol secret. -func (c *AnalyticsAdminClient) CreateMeasurementProtocolSecret(ctx context.Context, req *adminpb.CreateMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { - return c.internalClient.CreateMeasurementProtocolSecret(ctx, req, opts...) -} + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } -// DeleteMeasurementProtocolSecret deletes target MeasurementProtocolSecret. -func (c *AnalyticsAdminClient) DeleteMeasurementProtocolSecret(ctx context.Context, req *adminpb.DeleteMeasurementProtocolSecretRequest, opts ...gax.CallOption) error { - return c.internalClient.DeleteMeasurementProtocolSecret(ctx, req, opts...) -} + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetAccountSummaries(), resp.GetNextPageToken(), nil + } -// UpdateMeasurementProtocolSecret updates a measurement protocol secret. -func (c *AnalyticsAdminClient) UpdateMeasurementProtocolSecret(ctx context.Context, req *adminpb.UpdateMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { - return c.internalClient.UpdateMeasurementProtocolSecret(ctx, req, opts...) -} + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } -// AcknowledgeUserDataCollection acknowledges the terms of user data collection for the specified property. -// -// This acknowledgement must be completed (either in the Google Analytics UI -// or via this API) before MeasurementProtocolSecret resources may be created. -func (c *AnalyticsAdminClient) AcknowledgeUserDataCollection(ctx context.Context, req *adminpb.AcknowledgeUserDataCollectionRequest, opts ...gax.CallOption) (*adminpb.AcknowledgeUserDataCollectionResponse, error) { - return c.internalClient.AcknowledgeUserDataCollection(ctx, req, opts...) -} + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() -// SearchChangeHistoryEvents searches through all changes to an account or its children given the -// specified set of filters. -func (c *AnalyticsAdminClient) SearchChangeHistoryEvents(ctx context.Context, req *adminpb.SearchChangeHistoryEventsRequest, opts ...gax.CallOption) *ChangeHistoryEventIterator { - return c.internalClient.SearchChangeHistoryEvents(ctx, req, opts...) + return it } -// GetGoogleSignalsSettings lookup for Google Signals settings for a property. -func (c *AnalyticsAdminClient) GetGoogleSignalsSettings(ctx context.Context, req *adminpb.GetGoogleSignalsSettingsRequest, opts ...gax.CallOption) (*adminpb.GoogleSignalsSettings, error) { - return c.internalClient.GetGoogleSignalsSettings(ctx, req, opts...) -} +// GetProperty lookup for a single “GA4” Property. +func (c *analyticsAdminRESTClient) GetProperty(ctx context.Context, req *adminpb.GetPropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) -// UpdateGoogleSignalsSettings updates Google Signals settings for a property. -func (c *AnalyticsAdminClient) UpdateGoogleSignalsSettings(ctx context.Context, req *adminpb.UpdateGoogleSignalsSettingsRequest, opts ...gax.CallOption) (*adminpb.GoogleSignalsSettings, error) { - return c.internalClient.UpdateGoogleSignalsSettings(ctx, req, opts...) -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) -// CreateConversionEvent creates a conversion event with the specified attributes. -func (c *AnalyticsAdminClient) CreateConversionEvent(ctx context.Context, req *adminpb.CreateConversionEventRequest, opts ...gax.CallOption) (*adminpb.ConversionEvent, error) { - return c.internalClient.CreateConversionEvent(ctx, req, opts...) -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetProperty[0:len((*c.CallOptions).GetProperty):len((*c.CallOptions).GetProperty)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.Property{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// GetConversionEvent retrieve a single conversion event. -func (c *AnalyticsAdminClient) GetConversionEvent(ctx context.Context, req *adminpb.GetConversionEventRequest, opts ...gax.CallOption) (*adminpb.ConversionEvent, error) { - return c.internalClient.GetConversionEvent(ctx, req, opts...) -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// DeleteConversionEvent deletes a conversion event in a property. -func (c *AnalyticsAdminClient) DeleteConversionEvent(ctx context.Context, req *adminpb.DeleteConversionEventRequest, opts ...gax.CallOption) error { - return c.internalClient.DeleteConversionEvent(ctx, req, opts...) + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil } -// ListConversionEvents returns a list of conversion events in the specified parent property. +// ListProperties returns child Properties under the specified parent Account. // -// Returns an empty list if no conversion events are found. -func (c *AnalyticsAdminClient) ListConversionEvents(ctx context.Context, req *adminpb.ListConversionEventsRequest, opts ...gax.CallOption) *ConversionEventIterator { - return c.internalClient.ListConversionEvents(ctx, req, opts...) -} +// Only “GA4” properties will be returned. +// Properties will be excluded if the caller does not have access. +// Soft-deleted (ie: “trashed”) properties are excluded by default. +// Returns an empty list if no relevant properties are found. +func (c *analyticsAdminRESTClient) ListProperties(ctx context.Context, req *adminpb.ListPropertiesRequest, opts ...gax.CallOption) *PropertyIterator { + it := &PropertyIterator{} + req = proto.Clone(req).(*adminpb.ListPropertiesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.Property, string, error) { + resp := &adminpb.ListPropertiesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/properties") + + params := url.Values{} + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetShowDeleted() { + params.Add("showDeleted", fmt.Sprintf("%v", req.GetShowDeleted())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetProperties(), resp.GetNextPageToken(), nil + } -// GetDisplayVideo360AdvertiserLink look up a single DisplayVideo360AdvertiserLink -func (c *AnalyticsAdminClient) GetDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.GetDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { - return c.internalClient.GetDisplayVideo360AdvertiserLink(ctx, req, opts...) -} + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } -// ListDisplayVideo360AdvertiserLinks lists all DisplayVideo360AdvertiserLinks on a property. -func (c *AnalyticsAdminClient) ListDisplayVideo360AdvertiserLinks(ctx context.Context, req *adminpb.ListDisplayVideo360AdvertiserLinksRequest, opts ...gax.CallOption) *DisplayVideo360AdvertiserLinkIterator { - return c.internalClient.ListDisplayVideo360AdvertiserLinks(ctx, req, opts...) -} + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() -// CreateDisplayVideo360AdvertiserLink creates a DisplayVideo360AdvertiserLink. -// This can only be utilized by users who have proper authorization both on -// the Google Analytics property and on the Display & Video 360 advertiser. -// Users who do not have access to the Display & Video 360 advertiser should -// instead seek to create a DisplayVideo360LinkProposal. -func (c *AnalyticsAdminClient) CreateDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.CreateDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { - return c.internalClient.CreateDisplayVideo360AdvertiserLink(ctx, req, opts...) + return it } -// DeleteDisplayVideo360AdvertiserLink deletes a DisplayVideo360AdvertiserLink on a property. -func (c *AnalyticsAdminClient) DeleteDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.DeleteDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) error { - return c.internalClient.DeleteDisplayVideo360AdvertiserLink(ctx, req, opts...) -} +// CreateProperty creates an “GA4” property with the specified location and attributes. +func (c *analyticsAdminRESTClient) CreateProperty(ctx context.Context, req *adminpb.CreatePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetProperty() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } -// UpdateDisplayVideo360AdvertiserLink updates a DisplayVideo360AdvertiserLink on a property. -func (c *AnalyticsAdminClient) UpdateDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.UpdateDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { - return c.internalClient.UpdateDisplayVideo360AdvertiserLink(ctx, req, opts...) -} + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/properties") -// GetDisplayVideo360AdvertiserLinkProposal lookup for a single DisplayVideo360AdvertiserLinkProposal. -func (c *AnalyticsAdminClient) GetDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.GetDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { - return c.internalClient.GetDisplayVideo360AdvertiserLinkProposal(ctx, req, opts...) -} + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateProperty[0:len((*c.CallOptions).CreateProperty):len((*c.CallOptions).CreateProperty)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.Property{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// ListDisplayVideo360AdvertiserLinkProposals lists DisplayVideo360AdvertiserLinkProposals on a property. -func (c *AnalyticsAdminClient) ListDisplayVideo360AdvertiserLinkProposals(ctx context.Context, req *adminpb.ListDisplayVideo360AdvertiserLinkProposalsRequest, opts ...gax.CallOption) *DisplayVideo360AdvertiserLinkProposalIterator { - return c.internalClient.ListDisplayVideo360AdvertiserLinkProposals(ctx, req, opts...) -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// CreateDisplayVideo360AdvertiserLinkProposal creates a DisplayVideo360AdvertiserLinkProposal. -func (c *AnalyticsAdminClient) CreateDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.CreateDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { - return c.internalClient.CreateDisplayVideo360AdvertiserLinkProposal(ctx, req, opts...) -} + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } -// DeleteDisplayVideo360AdvertiserLinkProposal deletes a DisplayVideo360AdvertiserLinkProposal on a property. -// This can only be used on cancelled proposals. -func (c *AnalyticsAdminClient) DeleteDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.DeleteDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) error { - return c.internalClient.DeleteDisplayVideo360AdvertiserLinkProposal(ctx, req, opts...) -} + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } -// ApproveDisplayVideo360AdvertiserLinkProposal approves a DisplayVideo360AdvertiserLinkProposal. -// The DisplayVideo360AdvertiserLinkProposal will be deleted and a new -// DisplayVideo360AdvertiserLink will be created. -func (c *AnalyticsAdminClient) ApproveDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.ApproveDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.ApproveDisplayVideo360AdvertiserLinkProposalResponse, error) { - return c.internalClient.ApproveDisplayVideo360AdvertiserLinkProposal(ctx, req, opts...) + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil } -// CancelDisplayVideo360AdvertiserLinkProposal cancels a DisplayVideo360AdvertiserLinkProposal. -// Cancelling can mean either: +// DeleteProperty marks target Property as soft-deleted (ie: “trashed”) and returns it. // -// Declining a proposal initiated from Display & Video 360 +// This API does not have a method to restore soft-deleted properties. +// However, they can be restored using the Trash Can UI. // -// Withdrawing a proposal initiated from Google Analytics -// After being cancelled, a proposal will eventually be deleted automatically. -func (c *AnalyticsAdminClient) CancelDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.CancelDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { - return c.internalClient.CancelDisplayVideo360AdvertiserLinkProposal(ctx, req, opts...) -} +// If the properties are not restored before the expiration time, the Property +// and all child resources (eg: GoogleAdsLinks, Streams, UserLinks) +// will be permanently purged. +// https://support.google.com/analytics/answer/6154772 (at https://support.google.com/analytics/answer/6154772) +// +// Returns an error if the target is not found, or is not an GA4 Property. +func (c *analyticsAdminRESTClient) DeleteProperty(ctx context.Context, req *adminpb.DeletePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) -// CreateCustomDimension creates a CustomDimension. -func (c *AnalyticsAdminClient) CreateCustomDimension(ctx context.Context, req *adminpb.CreateCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { - return c.internalClient.CreateCustomDimension(ctx, req, opts...) -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) -// UpdateCustomDimension updates a CustomDimension on a property. -func (c *AnalyticsAdminClient) UpdateCustomDimension(ctx context.Context, req *adminpb.UpdateCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { - return c.internalClient.UpdateCustomDimension(ctx, req, opts...) -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).DeleteProperty[0:len((*c.CallOptions).DeleteProperty):len((*c.CallOptions).DeleteProperty)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.Property{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// ListCustomDimensions lists CustomDimensions on a property. -func (c *AnalyticsAdminClient) ListCustomDimensions(ctx context.Context, req *adminpb.ListCustomDimensionsRequest, opts ...gax.CallOption) *CustomDimensionIterator { - return c.internalClient.ListCustomDimensions(ctx, req, opts...) -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// ArchiveCustomDimension archives a CustomDimension on a property. -func (c *AnalyticsAdminClient) ArchiveCustomDimension(ctx context.Context, req *adminpb.ArchiveCustomDimensionRequest, opts ...gax.CallOption) error { - return c.internalClient.ArchiveCustomDimension(ctx, req, opts...) -} + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } -// GetCustomDimension lookup for a single CustomDimension. -func (c *AnalyticsAdminClient) GetCustomDimension(ctx context.Context, req *adminpb.GetCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { - return c.internalClient.GetCustomDimension(ctx, req, opts...) -} + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } -// CreateCustomMetric creates a CustomMetric. -func (c *AnalyticsAdminClient) CreateCustomMetric(ctx context.Context, req *adminpb.CreateCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { - return c.internalClient.CreateCustomMetric(ctx, req, opts...) -} + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } -// UpdateCustomMetric updates a CustomMetric on a property. -func (c *AnalyticsAdminClient) UpdateCustomMetric(ctx context.Context, req *adminpb.UpdateCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { - return c.internalClient.UpdateCustomMetric(ctx, req, opts...) + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil } -// ListCustomMetrics lists CustomMetrics on a property. -func (c *AnalyticsAdminClient) ListCustomMetrics(ctx context.Context, req *adminpb.ListCustomMetricsRequest, opts ...gax.CallOption) *CustomMetricIterator { - return c.internalClient.ListCustomMetrics(ctx, req, opts...) -} +// UpdateProperty updates a property. +func (c *analyticsAdminRESTClient) UpdateProperty(ctx context.Context, req *adminpb.UpdatePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetProperty() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } -// ArchiveCustomMetric archives a CustomMetric on a property. -func (c *AnalyticsAdminClient) ArchiveCustomMetric(ctx context.Context, req *adminpb.ArchiveCustomMetricRequest, opts ...gax.CallOption) error { - return c.internalClient.ArchiveCustomMetric(ctx, req, opts...) -} + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetProperty().GetName()) -// GetCustomMetric lookup for a single CustomMetric. -func (c *AnalyticsAdminClient) GetCustomMetric(ctx context.Context, req *adminpb.GetCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { - return c.internalClient.GetCustomMetric(ctx, req, opts...) -} + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } -// GetDataRetentionSettings returns the singleton data retention settings for this property. -func (c *AnalyticsAdminClient) GetDataRetentionSettings(ctx context.Context, req *adminpb.GetDataRetentionSettingsRequest, opts ...gax.CallOption) (*adminpb.DataRetentionSettings, error) { - return c.internalClient.GetDataRetentionSettings(ctx, req, opts...) -} + baseUrl.RawQuery = params.Encode() -// UpdateDataRetentionSettings updates the singleton data retention settings for this property. -func (c *AnalyticsAdminClient) UpdateDataRetentionSettings(ctx context.Context, req *adminpb.UpdateDataRetentionSettingsRequest, opts ...gax.CallOption) (*adminpb.DataRetentionSettings, error) { - return c.internalClient.UpdateDataRetentionSettings(ctx, req, opts...) -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "property.name", url.QueryEscape(req.GetProperty().GetName()))) -// CreateDataStream creates a DataStream. -func (c *AnalyticsAdminClient) CreateDataStream(ctx context.Context, req *adminpb.CreateDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { - return c.internalClient.CreateDataStream(ctx, req, opts...) -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateProperty[0:len((*c.CallOptions).UpdateProperty):len((*c.CallOptions).UpdateProperty)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.Property{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// DeleteDataStream deletes a DataStream on a property. -func (c *AnalyticsAdminClient) DeleteDataStream(ctx context.Context, req *adminpb.DeleteDataStreamRequest, opts ...gax.CallOption) error { - return c.internalClient.DeleteDataStream(ctx, req, opts...) -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// UpdateDataStream updates a DataStream on a property. -func (c *AnalyticsAdminClient) UpdateDataStream(ctx context.Context, req *adminpb.UpdateDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { - return c.internalClient.UpdateDataStream(ctx, req, opts...) -} + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } -// ListDataStreams lists DataStreams on a property. -func (c *AnalyticsAdminClient) ListDataStreams(ctx context.Context, req *adminpb.ListDataStreamsRequest, opts ...gax.CallOption) *DataStreamIterator { - return c.internalClient.ListDataStreams(ctx, req, opts...) -} + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } -// GetDataStream lookup for a single DataStream. -func (c *AnalyticsAdminClient) GetDataStream(ctx context.Context, req *adminpb.GetDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { - return c.internalClient.GetDataStream(ctx, req, opts...) + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil } -// analyticsAdminGRPCClient is a client for interacting with Google Analytics Admin API over gRPC transport. -// -// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. -type analyticsAdminGRPCClient struct { - // Connection pool of gRPC connections to the service. - connPool gtransport.ConnPool +// GetUserLink gets information about a user’s link to an account or property. +func (c *analyticsAdminRESTClient) GetUserLink(ctx context.Context, req *adminpb.GetUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) - // flag to opt out of default deadlines via GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE - disableDeadlines bool + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - // Points back to the CallOptions field of the containing AnalyticsAdminClient - CallOptions **AnalyticsAdminCallOptions + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetUserLink[0:len((*c.CallOptions).GetUserLink):len((*c.CallOptions).GetUserLink)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.UserLink{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers - // The gRPC API client. - analyticsAdminClient adminpb.AnalyticsAdminServiceClient + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() - // The x-goog-* metadata to be sent with each request. - xGoogMetadata metadata.MD -} + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } -// NewAnalyticsAdminClient creates a new analytics admin service client based on gRPC. -// The returned client must be Closed when it is done being used to clean up its underlying connections. -// -// Service Interface for the Analytics Admin API (GA4). -func NewAnalyticsAdminClient(ctx context.Context, opts ...option.ClientOption) (*AnalyticsAdminClient, error) { - clientOpts := defaultAnalyticsAdminGRPCClientOptions() - if newAnalyticsAdminClientHook != nil { - hookOpts, err := newAnalyticsAdminClientHook(ctx, clientHookParams{}) + buf, err := ioutil.ReadAll(httpRsp.Body) if err != nil { - return nil, err + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) } - clientOpts = append(clientOpts, hookOpts...) - } - disableDeadlines, err := checkDisableDeadlines() - if err != nil { - return nil, err + return nil + }, opts...) + if e != nil { + return nil, e } + return resp, nil +} - connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...) +// BatchGetUserLinks gets information about multiple users’ links to an account or property. +func (c *analyticsAdminRESTClient) BatchGetUserLinks(ctx context.Context, req *adminpb.BatchGetUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchGetUserLinksResponse, error) { + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, err } - client := AnalyticsAdminClient{CallOptions: defaultAnalyticsAdminCallOptions()} + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/userLinks:batchGet", req.GetParent()) - c := &analyticsAdminGRPCClient{ - connPool: connPool, - disableDeadlines: disableDeadlines, - analyticsAdminClient: adminpb.NewAnalyticsAdminServiceClient(connPool), - CallOptions: &client.CallOptions, + params := url.Values{} + if req.GetNames() != nil { + params.Add("names", fmt.Sprintf("%v", req.GetNames())) } - c.setGoogleClientInfo() - client.internalClient = c + baseUrl.RawQuery = params.Encode() - return &client, nil -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) -// Connection returns a connection to the API service. -// -// Deprecated. -func (c *analyticsAdminGRPCClient) Connection() *grpc.ClientConn { - return c.connPool.Conn() -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).BatchGetUserLinks[0:len((*c.CallOptions).BatchGetUserLinks):len((*c.CallOptions).BatchGetUserLinks)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.BatchGetUserLinksResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// setGoogleClientInfo sets the name and version of the application in -// the `x-goog-api-client` header passed on each request. Intended for -// use by Google-written clients. -func (c *analyticsAdminGRPCClient) setGoogleClientInfo(keyval ...string) { - kv := append([]string{"gl-go", versionGo()}, keyval...) - kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version) - c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// Close closes the connection to the API service. The user should invoke this when -// the client is no longer required. -func (c *analyticsAdminGRPCClient) Close() error { - return c.connPool.Close() -} + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } -func (c *analyticsAdminGRPCClient) GetAccount(ctx context.Context, req *adminpb.GetAccountRequest, opts ...gax.CallOption) (*adminpb.Account, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx - } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).GetAccount[0:len((*c.CallOptions).GetAccount):len((*c.CallOptions).GetAccount)], opts...) - var resp *adminpb.Account - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetAccount(ctx, req, settings.GRPC...) - return err + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) ListAccounts(ctx context.Context, req *adminpb.ListAccountsRequest, opts ...gax.CallOption) *AccountIterator { - ctx = insertMetadata(ctx, c.xGoogMetadata) - opts = append((*c.CallOptions).ListAccounts[0:len((*c.CallOptions).ListAccounts):len((*c.CallOptions).ListAccounts)], opts...) - it := &AccountIterator{} - req = proto.Clone(req).(*adminpb.ListAccountsRequest) - it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.Account, string, error) { - resp := &adminpb.ListAccountsResponse{} +// ListUserLinks lists all user links on an account or property. +func (c *analyticsAdminRESTClient) ListUserLinks(ctx context.Context, req *adminpb.ListUserLinksRequest, opts ...gax.CallOption) *UserLinkIterator { + it := &UserLinkIterator{} + req = proto.Clone(req).(*adminpb.ListUserLinksRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.UserLink, string, error) { + resp := &adminpb.ListUserLinksResponse{} if pageToken != "" { req.PageToken = pageToken } @@ -1634,18 +5174,62 @@ func (c *analyticsAdminGRPCClient) ListAccounts(ctx context.Context, req *adminp } else if pageSize != 0 { req.PageSize = int32(pageSize) } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ListAccounts(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, "", err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/userLinks", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } it.Response = resp - return resp.GetAccounts(), resp.GetNextPageToken(), nil + return resp.GetUserLinks(), resp.GetNextPageToken(), nil } + fetch := func(pageSize int, pageToken string) (string, error) { items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) if err != nil { @@ -1662,291 +5246,530 @@ func (c *analyticsAdminGRPCClient) ListAccounts(ctx context.Context, req *adminp return it } -func (c *analyticsAdminGRPCClient) DeleteAccount(ctx context.Context, req *adminpb.DeleteAccountRequest, opts ...gax.CallOption) error { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// AuditUserLinks lists all user links on an account or property, including implicit ones +// that come from effective permissions granted by groups or organization +// admin roles. +// +// If a returned user link does not have direct permissions, they cannot +// be removed from the account or property directly with the DeleteUserLink +// command. They have to be removed from the group/etc that gives them +// permissions, which is currently only usable/discoverable in the GA or GMP +// UIs. +func (c *analyticsAdminRESTClient) AuditUserLinks(ctx context.Context, req *adminpb.AuditUserLinksRequest, opts ...gax.CallOption) *AuditUserLinkIterator { + it := &AuditUserLinkIterator{} + req = proto.Clone(req).(*adminpb.AuditUserLinksRequest) + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.AuditUserLink, string, error) { + resp := &adminpb.AuditUserLinksResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, "", err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/userLinks:audit", req.GetParent()) + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetUserLinks(), resp.GetNextPageToken(), nil } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).DeleteAccount[0:len((*c.CallOptions).DeleteAccount):len((*c.CallOptions).DeleteAccount)], opts...) - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - _, err = c.analyticsAdminClient.DeleteAccount(ctx, req, settings.GRPC...) - return err - }, opts...) - return err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it } -func (c *analyticsAdminGRPCClient) UpdateAccount(ctx context.Context, req *adminpb.UpdateAccountRequest, opts ...gax.CallOption) (*adminpb.Account, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// CreateUserLink creates a user link on an account or property. +// +// If the user with the specified email already has permissions on the +// account or property, then the user’s existing permissions will be unioned +// with the permissions specified in the new UserLink. +func (c *analyticsAdminRESTClient) CreateUserLink(ctx context.Context, req *adminpb.CreateUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetUserLink() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "account.name", url.QueryEscape(req.GetAccount().GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).UpdateAccount[0:len((*c.CallOptions).UpdateAccount):len((*c.CallOptions).UpdateAccount)], opts...) - var resp *adminpb.Account - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.UpdateAccount(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/userLinks", req.GetParent()) + + params := url.Values{} + if req.GetNotifyNewUser() { + params.Add("notifyNewUser", fmt.Sprintf("%v", req.GetNotifyNewUser())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateUserLink[0:len((*c.CallOptions).CreateUserLink):len((*c.CallOptions).CreateUserLink)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.UserLink{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } return resp, nil } -func (c *analyticsAdminGRPCClient) ProvisionAccountTicket(ctx context.Context, req *adminpb.ProvisionAccountTicketRequest, opts ...gax.CallOption) (*adminpb.ProvisionAccountTicketResponse, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// BatchCreateUserLinks creates information about multiple users’ links to an account or property. +// +// This method is transactional. If any UserLink cannot be created, none of +// the UserLinks will be created. +func (c *analyticsAdminRESTClient) BatchCreateUserLinks(ctx context.Context, req *adminpb.BatchCreateUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchCreateUserLinksResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err } - ctx = insertMetadata(ctx, c.xGoogMetadata) - opts = append((*c.CallOptions).ProvisionAccountTicket[0:len((*c.CallOptions).ProvisionAccountTicket):len((*c.CallOptions).ProvisionAccountTicket)], opts...) - var resp *adminpb.ProvisionAccountTicketResponse - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ProvisionAccountTicket(ctx, req, settings.GRPC...) - return err + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/userLinks:batchCreate", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).BatchCreateUserLinks[0:len((*c.CallOptions).BatchCreateUserLinks):len((*c.CallOptions).BatchCreateUserLinks)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.BatchCreateUserLinksResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateUserLink updates a user link on an account or property. +func (c *analyticsAdminRESTClient) UpdateUserLink(ctx context.Context, req *adminpb.UpdateUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetUserLink() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, err } - return resp, nil -} + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetUserLink().GetName()) -func (c *analyticsAdminGRPCClient) ListAccountSummaries(ctx context.Context, req *adminpb.ListAccountSummariesRequest, opts ...gax.CallOption) *AccountSummaryIterator { - ctx = insertMetadata(ctx, c.xGoogMetadata) - opts = append((*c.CallOptions).ListAccountSummaries[0:len((*c.CallOptions).ListAccountSummaries):len((*c.CallOptions).ListAccountSummaries)], opts...) - it := &AccountSummaryIterator{} - req = proto.Clone(req).(*adminpb.ListAccountSummariesRequest) - it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.AccountSummary, string, error) { - resp := &adminpb.ListAccountSummariesResponse{} - if pageToken != "" { - req.PageToken = pageToken - } - if pageSize > math.MaxInt32 { - req.PageSize = math.MaxInt32 - } else if pageSize != 0 { - req.PageSize = int32(pageSize) + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "user_link.name", url.QueryEscape(req.GetUserLink().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateUserLink[0:len((*c.CallOptions).UpdateUserLink):len((*c.CallOptions).UpdateUserLink)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.UserLink{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ListAccountSummaries(ctx, req, settings.GRPC...) + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { return err - }, opts...) + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) if err != nil { - return nil, "", err + return err } + defer httpRsp.Body.Close() - it.Response = resp - return resp.GetAccountSummaries(), resp.GetNextPageToken(), nil - } - fetch := func(pageSize int, pageToken string) (string, error) { - items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) if err != nil { - return "", err + return err } - it.items = append(it.items, items...) - return nextPageToken, nil - } - it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) - it.pageInfo.MaxSize = int(req.GetPageSize()) - it.pageInfo.Token = req.GetPageToken() + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } - return it + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil } -func (c *analyticsAdminGRPCClient) GetProperty(ctx context.Context, req *adminpb.GetPropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// BatchUpdateUserLinks updates information about multiple users’ links to an account or property. +func (c *analyticsAdminRESTClient) BatchUpdateUserLinks(ctx context.Context, req *adminpb.BatchUpdateUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchUpdateUserLinksResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).GetProperty[0:len((*c.CallOptions).GetProperty):len((*c.CallOptions).GetProperty)], opts...) - var resp *adminpb.Property - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetProperty(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, err } - return resp, nil -} + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/userLinks:batchUpdate", req.GetParent()) -func (c *analyticsAdminGRPCClient) ListProperties(ctx context.Context, req *adminpb.ListPropertiesRequest, opts ...gax.CallOption) *PropertyIterator { - ctx = insertMetadata(ctx, c.xGoogMetadata) - opts = append((*c.CallOptions).ListProperties[0:len((*c.CallOptions).ListProperties):len((*c.CallOptions).ListProperties)], opts...) - it := &PropertyIterator{} - req = proto.Clone(req).(*adminpb.ListPropertiesRequest) - it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.Property, string, error) { - resp := &adminpb.ListPropertiesResponse{} - if pageToken != "" { - req.PageToken = pageToken - } - if pageSize > math.MaxInt32 { - req.PageSize = math.MaxInt32 - } else if pageSize != 0 { - req.PageSize = int32(pageSize) + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).BatchUpdateUserLinks[0:len((*c.CallOptions).BatchUpdateUserLinks):len((*c.CallOptions).BatchUpdateUserLinks)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.BatchUpdateUserLinksResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ListProperties(ctx, req, settings.GRPC...) - return err - }, opts...) + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) if err != nil { - return nil, "", err + return err } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers - it.Response = resp - return resp.GetProperties(), resp.GetNextPageToken(), nil - } - fetch := func(pageSize int, pageToken string) (string, error) { - items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + httpRsp, err := c.httpClient.Do(httpReq) if err != nil { - return "", err + return err } - it.items = append(it.items, items...) - return nextPageToken, nil - } + defer httpRsp.Body.Close() - it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) - it.pageInfo.MaxSize = int(req.GetPageSize()) - it.pageInfo.Token = req.GetPageToken() + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } - return it -} + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } -func (c *analyticsAdminGRPCClient) CreateProperty(ctx context.Context, req *adminpb.CreatePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx - } - ctx = insertMetadata(ctx, c.xGoogMetadata) - opts = append((*c.CallOptions).CreateProperty[0:len((*c.CallOptions).CreateProperty):len((*c.CallOptions).CreateProperty)], opts...) - var resp *adminpb.Property - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.CreateProperty(ctx, req, settings.GRPC...) - return err + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) DeleteProperty(ctx context.Context, req *adminpb.DeletePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// DeleteUserLink deletes a user link on an account or property. +func (c *analyticsAdminRESTClient) DeleteUserLink(ctx context.Context, req *adminpb.DeleteUserLinkRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).DeleteProperty[0:len((*c.CallOptions).DeleteProperty):len((*c.CallOptions).DeleteProperty)], opts...) - var resp *adminpb.Property - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.DeleteProperty(ctx, req, settings.GRPC...) - return err + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) }, opts...) - if err != nil { - return nil, err - } - return resp, nil } -func (c *analyticsAdminGRPCClient) UpdateProperty(ctx context.Context, req *adminpb.UpdatePropertyRequest, opts ...gax.CallOption) (*adminpb.Property, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// BatchDeleteUserLinks deletes information about multiple users’ links to an account or property. +func (c *analyticsAdminRESTClient) BatchDeleteUserLinks(ctx context.Context, req *adminpb.BatchDeleteUserLinksRequest, opts ...gax.CallOption) error { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return err } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "property.name", url.QueryEscape(req.GetProperty().GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).UpdateProperty[0:len((*c.CallOptions).UpdateProperty):len((*c.CallOptions).UpdateProperty)], opts...) - var resp *adminpb.Property - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.UpdateProperty(ctx, req, settings.GRPC...) + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/userLinks:batchDelete", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) }, opts...) +} + +// CreateFirebaseLink creates a FirebaseLink. +// +// Properties can have at most one FirebaseLink. +func (c *analyticsAdminRESTClient) CreateFirebaseLink(ctx context.Context, req *adminpb.CreateFirebaseLinkRequest, opts ...gax.CallOption) (*adminpb.FirebaseLink, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetFirebaseLink() + jsonReq, err := m.Marshal(body) if err != nil { return nil, err } - return resp, nil -} -func (c *analyticsAdminGRPCClient) GetUserLink(ctx context.Context, req *adminpb.GetUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/firebaseLinks", req.GetParent()) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).GetUserLink[0:len((*c.CallOptions).GetUserLink):len((*c.CallOptions).GetUserLink)], opts...) - var resp *adminpb.UserLink - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetUserLink(ctx, req, settings.GRPC...) - return err + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateFirebaseLink[0:len((*c.CallOptions).CreateFirebaseLink):len((*c.CallOptions).CreateFirebaseLink)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.FirebaseLink{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) BatchGetUserLinks(ctx context.Context, req *adminpb.BatchGetUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchGetUserLinksResponse, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// DeleteFirebaseLink deletes a FirebaseLink on a property +func (c *analyticsAdminRESTClient) DeleteFirebaseLink(ctx context.Context, req *adminpb.DeleteFirebaseLinkRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).BatchGetUserLinks[0:len((*c.CallOptions).BatchGetUserLinks):len((*c.CallOptions).BatchGetUserLinks)], opts...) - var resp *adminpb.BatchGetUserLinksResponse - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.BatchGetUserLinks(ctx, req, settings.GRPC...) - return err + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) }, opts...) - if err != nil { - return nil, err - } - return resp, nil } -func (c *analyticsAdminGRPCClient) ListUserLinks(ctx context.Context, req *adminpb.ListUserLinksRequest, opts ...gax.CallOption) *UserLinkIterator { - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).ListUserLinks[0:len((*c.CallOptions).ListUserLinks):len((*c.CallOptions).ListUserLinks)], opts...) - it := &UserLinkIterator{} - req = proto.Clone(req).(*adminpb.ListUserLinksRequest) - it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.UserLink, string, error) { - resp := &adminpb.ListUserLinksResponse{} +// ListFirebaseLinks lists FirebaseLinks on a property. +// Properties can have at most one FirebaseLink. +func (c *analyticsAdminRESTClient) ListFirebaseLinks(ctx context.Context, req *adminpb.ListFirebaseLinksRequest, opts ...gax.CallOption) *FirebaseLinkIterator { + it := &FirebaseLinkIterator{} + req = proto.Clone(req).(*adminpb.ListFirebaseLinksRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.FirebaseLink, string, error) { + resp := &adminpb.ListFirebaseLinksResponse{} if pageToken != "" { req.PageToken = pageToken } @@ -1955,18 +5778,62 @@ func (c *analyticsAdminGRPCClient) ListUserLinks(ctx context.Context, req *admin } else if pageSize != 0 { req.PageSize = int32(pageSize) } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ListUserLinks(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, "", err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/firebaseLinks", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } it.Response = resp - return resp.GetUserLinks(), resp.GetNextPageToken(), nil + return resp.GetFirebaseLinks(), resp.GetNextPageToken(), nil } + fetch := func(pageSize int, pageToken string) (string, error) { items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) if err != nil { @@ -1983,224 +5850,229 @@ func (c *analyticsAdminGRPCClient) ListUserLinks(ctx context.Context, req *admin return it } -func (c *analyticsAdminGRPCClient) AuditUserLinks(ctx context.Context, req *adminpb.AuditUserLinksRequest, opts ...gax.CallOption) *AuditUserLinkIterator { - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) +// GetGlobalSiteTag returns the Site Tag for the specified web stream. +// Site Tags are immutable singletons. +func (c *analyticsAdminRESTClient) GetGlobalSiteTag(ctx context.Context, req *adminpb.GetGlobalSiteTagRequest, opts ...gax.CallOption) (*adminpb.GlobalSiteTag, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).AuditUserLinks[0:len((*c.CallOptions).AuditUserLinks):len((*c.CallOptions).AuditUserLinks)], opts...) - it := &AuditUserLinkIterator{} - req = proto.Clone(req).(*adminpb.AuditUserLinksRequest) - it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.AuditUserLink, string, error) { - resp := &adminpb.AuditUserLinksResponse{} - if pageToken != "" { - req.PageToken = pageToken - } - if pageSize > math.MaxInt32 { - req.PageSize = math.MaxInt32 - } else if pageSize != 0 { - req.PageSize = int32(pageSize) + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetGlobalSiteTag[0:len((*c.CallOptions).GetGlobalSiteTag):len((*c.CallOptions).GetGlobalSiteTag)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.GlobalSiteTag{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.AuditUserLinks(ctx, req, settings.GRPC...) - return err - }, opts...) + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) if err != nil { - return nil, "", err + return err } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers - it.Response = resp - return resp.GetUserLinks(), resp.GetNextPageToken(), nil - } - fetch := func(pageSize int, pageToken string) (string, error) { - items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + httpRsp, err := c.httpClient.Do(httpReq) if err != nil { - return "", err + return err } - it.items = append(it.items, items...) - return nextPageToken, nil - } + defer httpRsp.Body.Close() - it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) - it.pageInfo.MaxSize = int(req.GetPageSize()) - it.pageInfo.Token = req.GetPageToken() + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } - return it -} + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } -func (c *analyticsAdminGRPCClient) CreateUserLink(ctx context.Context, req *adminpb.CreateUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx - } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).CreateUserLink[0:len((*c.CallOptions).CreateUserLink):len((*c.CallOptions).CreateUserLink)], opts...) - var resp *adminpb.UserLink - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.CreateUserLink(ctx, req, settings.GRPC...) - return err + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) BatchCreateUserLinks(ctx context.Context, req *adminpb.BatchCreateUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchCreateUserLinksResponse, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// CreateGoogleAdsLink creates a GoogleAdsLink. +func (c *analyticsAdminRESTClient) CreateGoogleAdsLink(ctx context.Context, req *adminpb.CreateGoogleAdsLinkRequest, opts ...gax.CallOption) (*adminpb.GoogleAdsLink, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetGoogleAdsLink() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).BatchCreateUserLinks[0:len((*c.CallOptions).BatchCreateUserLinks):len((*c.CallOptions).BatchCreateUserLinks)], opts...) - var resp *adminpb.BatchCreateUserLinksResponse - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.BatchCreateUserLinks(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, err } - return resp, nil -} + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/googleAdsLinks", req.GetParent()) -func (c *analyticsAdminGRPCClient) UpdateUserLink(ctx context.Context, req *adminpb.UpdateUserLinkRequest, opts ...gax.CallOption) (*adminpb.UserLink, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx - } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "user_link.name", url.QueryEscape(req.GetUserLink().GetName()))) + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).UpdateUserLink[0:len((*c.CallOptions).UpdateUserLink):len((*c.CallOptions).UpdateUserLink)], opts...) - var resp *adminpb.UserLink - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.UpdateUserLink(ctx, req, settings.GRPC...) - return err + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateGoogleAdsLink[0:len((*c.CallOptions).CreateGoogleAdsLink):len((*c.CallOptions).CreateGoogleAdsLink)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.GoogleAdsLink{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) BatchUpdateUserLinks(ctx context.Context, req *adminpb.BatchUpdateUserLinksRequest, opts ...gax.CallOption) (*adminpb.BatchUpdateUserLinksResponse, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// UpdateGoogleAdsLink updates a GoogleAdsLink on a property +func (c *analyticsAdminRESTClient) UpdateGoogleAdsLink(ctx context.Context, req *adminpb.UpdateGoogleAdsLinkRequest, opts ...gax.CallOption) (*adminpb.GoogleAdsLink, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetGoogleAdsLink() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).BatchUpdateUserLinks[0:len((*c.CallOptions).BatchUpdateUserLinks):len((*c.CallOptions).BatchUpdateUserLinks)], opts...) - var resp *adminpb.BatchUpdateUserLinksResponse - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.BatchUpdateUserLinks(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, err } - return resp, nil -} + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetGoogleAdsLink().GetName()) -func (c *analyticsAdminGRPCClient) DeleteUserLink(ctx context.Context, req *adminpb.DeleteUserLinkRequest, opts ...gax.CallOption) error { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).DeleteUserLink[0:len((*c.CallOptions).DeleteUserLink):len((*c.CallOptions).DeleteUserLink)], opts...) - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - _, err = c.analyticsAdminClient.DeleteUserLink(ctx, req, settings.GRPC...) - return err - }, opts...) - return err -} + baseUrl.RawQuery = params.Encode() -func (c *analyticsAdminGRPCClient) BatchDeleteUserLinks(ctx context.Context, req *adminpb.BatchDeleteUserLinksRequest, opts ...gax.CallOption) error { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx - } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "google_ads_link.name", url.QueryEscape(req.GetGoogleAdsLink().GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).BatchDeleteUserLinks[0:len((*c.CallOptions).BatchDeleteUserLinks):len((*c.CallOptions).BatchDeleteUserLinks)], opts...) - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - _, err = c.analyticsAdminClient.BatchDeleteUserLinks(ctx, req, settings.GRPC...) - return err - }, opts...) - return err -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateGoogleAdsLink[0:len((*c.CallOptions).UpdateGoogleAdsLink):len((*c.CallOptions).UpdateGoogleAdsLink)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.GoogleAdsLink{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -func (c *analyticsAdminGRPCClient) CreateFirebaseLink(ctx context.Context, req *adminpb.CreateFirebaseLinkRequest, opts ...gax.CallOption) (*adminpb.FirebaseLink, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx - } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).CreateFirebaseLink[0:len((*c.CallOptions).CreateFirebaseLink):len((*c.CallOptions).CreateFirebaseLink)], opts...) - var resp *adminpb.FirebaseLink - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.CreateFirebaseLink(ctx, req, settings.GRPC...) - return err + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) DeleteFirebaseLink(ctx context.Context, req *adminpb.DeleteFirebaseLinkRequest, opts ...gax.CallOption) error { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// DeleteGoogleAdsLink deletes a GoogleAdsLink on a property +func (c *analyticsAdminRESTClient) DeleteGoogleAdsLink(ctx context.Context, req *adminpb.DeleteGoogleAdsLinkRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).DeleteFirebaseLink[0:len((*c.CallOptions).DeleteFirebaseLink):len((*c.CallOptions).DeleteFirebaseLink)], opts...) - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - _, err = c.analyticsAdminClient.DeleteFirebaseLink(ctx, req, settings.GRPC...) - return err + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) }, opts...) - return err } -func (c *analyticsAdminGRPCClient) ListFirebaseLinks(ctx context.Context, req *adminpb.ListFirebaseLinksRequest, opts ...gax.CallOption) *FirebaseLinkIterator { - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).ListFirebaseLinks[0:len((*c.CallOptions).ListFirebaseLinks):len((*c.CallOptions).ListFirebaseLinks)], opts...) - it := &FirebaseLinkIterator{} - req = proto.Clone(req).(*adminpb.ListFirebaseLinksRequest) - it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.FirebaseLink, string, error) { - resp := &adminpb.ListFirebaseLinksResponse{} +// ListGoogleAdsLinks lists GoogleAdsLinks on a property. +func (c *analyticsAdminRESTClient) ListGoogleAdsLinks(ctx context.Context, req *adminpb.ListGoogleAdsLinksRequest, opts ...gax.CallOption) *GoogleAdsLinkIterator { + it := &GoogleAdsLinkIterator{} + req = proto.Clone(req).(*adminpb.ListGoogleAdsLinksRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.GoogleAdsLink, string, error) { + resp := &adminpb.ListGoogleAdsLinksResponse{} if pageToken != "" { req.PageToken = pageToken } @@ -2209,18 +6081,62 @@ func (c *analyticsAdminGRPCClient) ListFirebaseLinks(ctx context.Context, req *a } else if pageSize != 0 { req.PageSize = int32(pageSize) } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ListFirebaseLinks(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, "", err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/googleAdsLinks", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } it.Response = resp - return resp.GetFirebaseLinks(), resp.GetNextPageToken(), nil + return resp.GetGoogleAdsLinks(), resp.GetNextPageToken(), nil } + fetch := func(pageSize int, pageToken string) (string, error) { items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) if err != nil { @@ -2237,99 +6153,121 @@ func (c *analyticsAdminGRPCClient) ListFirebaseLinks(ctx context.Context, req *a return it } -func (c *analyticsAdminGRPCClient) GetGlobalSiteTag(ctx context.Context, req *adminpb.GetGlobalSiteTagRequest, opts ...gax.CallOption) (*adminpb.GlobalSiteTag, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx - } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).GetGlobalSiteTag[0:len((*c.CallOptions).GetGlobalSiteTag):len((*c.CallOptions).GetGlobalSiteTag)], opts...) - var resp *adminpb.GlobalSiteTag - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetGlobalSiteTag(ctx, req, settings.GRPC...) - return err - }, opts...) +// GetDataSharingSettings get data sharing settings on an account. +// Data sharing settings are singletons. +func (c *analyticsAdminRESTClient) GetDataSharingSettings(ctx context.Context, req *adminpb.GetDataSharingSettingsRequest, opts ...gax.CallOption) (*adminpb.DataSharingSettings, error) { + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, err } - return resp, nil -} + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) -func (c *analyticsAdminGRPCClient) CreateGoogleAdsLink(ctx context.Context, req *adminpb.CreateGoogleAdsLinkRequest, opts ...gax.CallOption) (*adminpb.GoogleAdsLink, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx - } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).CreateGoogleAdsLink[0:len((*c.CallOptions).CreateGoogleAdsLink):len((*c.CallOptions).CreateGoogleAdsLink)], opts...) - var resp *adminpb.GoogleAdsLink - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.CreateGoogleAdsLink(ctx, req, settings.GRPC...) - return err + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetDataSharingSettings[0:len((*c.CallOptions).GetDataSharingSettings):len((*c.CallOptions).GetDataSharingSettings)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.DataSharingSettings{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) UpdateGoogleAdsLink(ctx context.Context, req *adminpb.UpdateGoogleAdsLinkRequest, opts ...gax.CallOption) (*adminpb.GoogleAdsLink, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx - } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "google_ads_link.name", url.QueryEscape(req.GetGoogleAdsLink().GetName()))) - - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).UpdateGoogleAdsLink[0:len((*c.CallOptions).UpdateGoogleAdsLink):len((*c.CallOptions).UpdateGoogleAdsLink)], opts...) - var resp *adminpb.GoogleAdsLink - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.UpdateGoogleAdsLink(ctx, req, settings.GRPC...) - return err - }, opts...) +// GetMeasurementProtocolSecret lookup for a single “GA4” MeasurementProtocolSecret. +func (c *analyticsAdminRESTClient) GetMeasurementProtocolSecret(ctx context.Context, req *adminpb.GetMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, err } - return resp, nil -} + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) -func (c *analyticsAdminGRPCClient) DeleteGoogleAdsLink(ctx context.Context, req *adminpb.DeleteGoogleAdsLinkRequest, opts ...gax.CallOption) error { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx - } + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).DeleteGoogleAdsLink[0:len((*c.CallOptions).DeleteGoogleAdsLink):len((*c.CallOptions).DeleteGoogleAdsLink)], opts...) - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - _, err = c.analyticsAdminClient.DeleteGoogleAdsLink(ctx, req, settings.GRPC...) - return err + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetMeasurementProtocolSecret[0:len((*c.CallOptions).GetMeasurementProtocolSecret):len((*c.CallOptions).GetMeasurementProtocolSecret)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.MeasurementProtocolSecret{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - return err + if e != nil { + return nil, e + } + return resp, nil } -func (c *analyticsAdminGRPCClient) ListGoogleAdsLinks(ctx context.Context, req *adminpb.ListGoogleAdsLinksRequest, opts ...gax.CallOption) *GoogleAdsLinkIterator { - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).ListGoogleAdsLinks[0:len((*c.CallOptions).ListGoogleAdsLinks):len((*c.CallOptions).ListGoogleAdsLinks)], opts...) - it := &GoogleAdsLinkIterator{} - req = proto.Clone(req).(*adminpb.ListGoogleAdsLinksRequest) - it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.GoogleAdsLink, string, error) { - resp := &adminpb.ListGoogleAdsLinksResponse{} +// ListMeasurementProtocolSecrets returns child MeasurementProtocolSecrets under the specified parent +// Property. +func (c *analyticsAdminRESTClient) ListMeasurementProtocolSecrets(ctx context.Context, req *adminpb.ListMeasurementProtocolSecretsRequest, opts ...gax.CallOption) *MeasurementProtocolSecretIterator { + it := &MeasurementProtocolSecretIterator{} + req = proto.Clone(req).(*adminpb.ListMeasurementProtocolSecretsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.MeasurementProtocolSecret, string, error) { + resp := &adminpb.ListMeasurementProtocolSecretsResponse{} if pageToken != "" { req.PageToken = pageToken } @@ -2338,18 +6276,62 @@ func (c *analyticsAdminGRPCClient) ListGoogleAdsLinks(ctx context.Context, req * } else if pageSize != 0 { req.PageSize = int32(pageSize) } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ListGoogleAdsLinks(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, "", err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/measurementProtocolSecrets", req.GetParent()) + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } it.Response = resp - return resp.GetGoogleAdsLinks(), resp.GetNextPageToken(), nil + return resp.GetMeasurementProtocolSecrets(), resp.GetNextPageToken(), nil } + fetch := func(pageSize int, pageToken string) (string, error) { items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) if err != nil { @@ -2366,186 +6348,237 @@ func (c *analyticsAdminGRPCClient) ListGoogleAdsLinks(ctx context.Context, req * return it } -func (c *analyticsAdminGRPCClient) GetDataSharingSettings(ctx context.Context, req *adminpb.GetDataSharingSettingsRequest, opts ...gax.CallOption) (*adminpb.DataSharingSettings, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx - } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).GetDataSharingSettings[0:len((*c.CallOptions).GetDataSharingSettings):len((*c.CallOptions).GetDataSharingSettings)], opts...) - var resp *adminpb.DataSharingSettings - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetDataSharingSettings(ctx, req, settings.GRPC...) - return err - }, opts...) +// CreateMeasurementProtocolSecret creates a measurement protocol secret. +func (c *analyticsAdminRESTClient) CreateMeasurementProtocolSecret(ctx context.Context, req *adminpb.CreateMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetMeasurementProtocolSecret() + jsonReq, err := m.Marshal(body) if err != nil { return nil, err } - return resp, nil -} - -func (c *analyticsAdminGRPCClient) GetMeasurementProtocolSecret(ctx context.Context, req *adminpb.GetMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx - } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).GetMeasurementProtocolSecret[0:len((*c.CallOptions).GetMeasurementProtocolSecret):len((*c.CallOptions).GetMeasurementProtocolSecret)], opts...) - var resp *adminpb.MeasurementProtocolSecret - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetMeasurementProtocolSecret(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, err } - return resp, nil -} + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/measurementProtocolSecrets", req.GetParent()) -func (c *analyticsAdminGRPCClient) ListMeasurementProtocolSecrets(ctx context.Context, req *adminpb.ListMeasurementProtocolSecretsRequest, opts ...gax.CallOption) *MeasurementProtocolSecretIterator { + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).ListMeasurementProtocolSecrets[0:len((*c.CallOptions).ListMeasurementProtocolSecrets):len((*c.CallOptions).ListMeasurementProtocolSecrets)], opts...) - it := &MeasurementProtocolSecretIterator{} - req = proto.Clone(req).(*adminpb.ListMeasurementProtocolSecretsRequest) - it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.MeasurementProtocolSecret, string, error) { - resp := &adminpb.ListMeasurementProtocolSecretsResponse{} - if pageToken != "" { - req.PageToken = pageToken + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateMeasurementProtocolSecret[0:len((*c.CallOptions).CreateMeasurementProtocolSecret):len((*c.CallOptions).CreateMeasurementProtocolSecret)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.MeasurementProtocolSecret{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path } - if pageSize > math.MaxInt32 { - req.PageSize = math.MaxInt32 - } else if pageSize != 0 { - req.PageSize = int32(pageSize) + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ListMeasurementProtocolSecrets(ctx, req, settings.GRPC...) + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { return err - }, opts...) + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteMeasurementProtocolSecret deletes target MeasurementProtocolSecret. +func (c *analyticsAdminRESTClient) DeleteMeasurementProtocolSecret(ctx context.Context, req *adminpb.DeleteMeasurementProtocolSecretRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) if err != nil { - return nil, "", err + return err } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers - it.Response = resp - return resp.GetMeasurementProtocolSecrets(), resp.GetNextPageToken(), nil - } - fetch := func(pageSize int, pageToken string) (string, error) { - items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + httpRsp, err := c.httpClient.Do(httpReq) if err != nil { - return "", err + return err } - it.items = append(it.items, items...) - return nextPageToken, nil - } - - it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) - it.pageInfo.MaxSize = int(req.GetPageSize()) - it.pageInfo.Token = req.GetPageToken() + defer httpRsp.Body.Close() - return it + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) } -func (c *analyticsAdminGRPCClient) CreateMeasurementProtocolSecret(ctx context.Context, req *adminpb.CreateMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// UpdateMeasurementProtocolSecret updates a measurement protocol secret. +func (c *analyticsAdminRESTClient) UpdateMeasurementProtocolSecret(ctx context.Context, req *adminpb.UpdateMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetMeasurementProtocolSecret() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).CreateMeasurementProtocolSecret[0:len((*c.CallOptions).CreateMeasurementProtocolSecret):len((*c.CallOptions).CreateMeasurementProtocolSecret)], opts...) - var resp *adminpb.MeasurementProtocolSecret - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.CreateMeasurementProtocolSecret(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, err } - return resp, nil -} + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetMeasurementProtocolSecret().GetName()) -func (c *analyticsAdminGRPCClient) DeleteMeasurementProtocolSecret(ctx context.Context, req *adminpb.DeleteMeasurementProtocolSecretRequest, opts ...gax.CallOption) error { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).DeleteMeasurementProtocolSecret[0:len((*c.CallOptions).DeleteMeasurementProtocolSecret):len((*c.CallOptions).DeleteMeasurementProtocolSecret)], opts...) - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - _, err = c.analyticsAdminClient.DeleteMeasurementProtocolSecret(ctx, req, settings.GRPC...) - return err - }, opts...) - return err -} + baseUrl.RawQuery = params.Encode() -func (c *analyticsAdminGRPCClient) UpdateMeasurementProtocolSecret(ctx context.Context, req *adminpb.UpdateMeasurementProtocolSecretRequest, opts ...gax.CallOption) (*adminpb.MeasurementProtocolSecret, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx - } + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "measurement_protocol_secret.name", url.QueryEscape(req.GetMeasurementProtocolSecret().GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).UpdateMeasurementProtocolSecret[0:len((*c.CallOptions).UpdateMeasurementProtocolSecret):len((*c.CallOptions).UpdateMeasurementProtocolSecret)], opts...) - var resp *adminpb.MeasurementProtocolSecret - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.UpdateMeasurementProtocolSecret(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.MeasurementProtocolSecret{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) AcknowledgeUserDataCollection(ctx context.Context, req *adminpb.AcknowledgeUserDataCollectionRequest, opts ...gax.CallOption) (*adminpb.AcknowledgeUserDataCollectionResponse, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// AcknowledgeUserDataCollection acknowledges the terms of user data collection for the specified property. +// +// This acknowledgement must be completed (either in the Google Analytics UI +// or via this API) before MeasurementProtocolSecret resources may be created. +func (c *analyticsAdminRESTClient) AcknowledgeUserDataCollection(ctx context.Context, req *adminpb.AcknowledgeUserDataCollectionRequest, opts ...gax.CallOption) (*adminpb.AcknowledgeUserDataCollectionResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v:acknowledgeUserDataCollection", req.GetProperty()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "property", url.QueryEscape(req.GetProperty()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).AcknowledgeUserDataCollection[0:len((*c.CallOptions).AcknowledgeUserDataCollection):len((*c.CallOptions).AcknowledgeUserDataCollection)], opts...) - var resp *adminpb.AcknowledgeUserDataCollectionResponse - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.AcknowledgeUserDataCollection(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.AcknowledgeUserDataCollectionResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) SearchChangeHistoryEvents(ctx context.Context, req *adminpb.SearchChangeHistoryEventsRequest, opts ...gax.CallOption) *ChangeHistoryEventIterator { - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "account", url.QueryEscape(req.GetAccount()))) - - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).SearchChangeHistoryEvents[0:len((*c.CallOptions).SearchChangeHistoryEvents):len((*c.CallOptions).SearchChangeHistoryEvents)], opts...) +// SearchChangeHistoryEvents searches through all changes to an account or its children given the +// specified set of filters. +func (c *analyticsAdminRESTClient) SearchChangeHistoryEvents(ctx context.Context, req *adminpb.SearchChangeHistoryEventsRequest, opts ...gax.CallOption) *ChangeHistoryEventIterator { it := &ChangeHistoryEventIterator{} req = proto.Clone(req).(*adminpb.SearchChangeHistoryEventsRequest) + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.ChangeHistoryEvent, string, error) { resp := &adminpb.SearchChangeHistoryEventsResponse{} if pageToken != "" { @@ -2556,18 +6589,57 @@ func (c *analyticsAdminGRPCClient) SearchChangeHistoryEvents(ctx context.Context } else if pageSize != 0 { req.PageSize = int32(pageSize) } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.SearchChangeHistoryEvents(ctx, req, settings.GRPC...) - return err - }, opts...) + jsonReq, err := m.Marshal(req) if err != nil { return nil, "", err } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v:searchChangeHistoryEvents", req.GetAccount()) + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } it.Response = resp return resp.GetChangeHistoryEvents(), resp.GetNextPageToken(), nil } + fetch := func(pageSize int, pageToken string) (string, error) { items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) if err != nil { @@ -2584,119 +6656,281 @@ func (c *analyticsAdminGRPCClient) SearchChangeHistoryEvents(ctx context.Context return it } -func (c *analyticsAdminGRPCClient) GetGoogleSignalsSettings(ctx context.Context, req *adminpb.GetGoogleSignalsSettingsRequest, opts ...gax.CallOption) (*adminpb.GoogleSignalsSettings, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// GetGoogleSignalsSettings lookup for Google Signals settings for a property. +func (c *analyticsAdminRESTClient) GetGoogleSignalsSettings(ctx context.Context, req *adminpb.GetGoogleSignalsSettingsRequest, opts ...gax.CallOption) (*adminpb.GoogleSignalsSettings, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).GetGoogleSignalsSettings[0:len((*c.CallOptions).GetGoogleSignalsSettings):len((*c.CallOptions).GetGoogleSignalsSettings)], opts...) - var resp *adminpb.GoogleSignalsSettings - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetGoogleSignalsSettings(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.GoogleSignalsSettings{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) UpdateGoogleSignalsSettings(ctx context.Context, req *adminpb.UpdateGoogleSignalsSettingsRequest, opts ...gax.CallOption) (*adminpb.GoogleSignalsSettings, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// UpdateGoogleSignalsSettings updates Google Signals settings for a property. +func (c *analyticsAdminRESTClient) UpdateGoogleSignalsSettings(ctx context.Context, req *adminpb.UpdateGoogleSignalsSettingsRequest, opts ...gax.CallOption) (*adminpb.GoogleSignalsSettings, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetGoogleSignalsSettings() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetGoogleSignalsSettings().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "google_signals_settings.name", url.QueryEscape(req.GetGoogleSignalsSettings().GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).UpdateGoogleSignalsSettings[0:len((*c.CallOptions).UpdateGoogleSignalsSettings):len((*c.CallOptions).UpdateGoogleSignalsSettings)], opts...) - var resp *adminpb.GoogleSignalsSettings - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.UpdateGoogleSignalsSettings(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.GoogleSignalsSettings{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) CreateConversionEvent(ctx context.Context, req *adminpb.CreateConversionEventRequest, opts ...gax.CallOption) (*adminpb.ConversionEvent, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// CreateConversionEvent creates a conversion event with the specified attributes. +func (c *analyticsAdminRESTClient) CreateConversionEvent(ctx context.Context, req *adminpb.CreateConversionEventRequest, opts ...gax.CallOption) (*adminpb.ConversionEvent, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetConversionEvent() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/conversionEvents", req.GetParent()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).CreateConversionEvent[0:len((*c.CallOptions).CreateConversionEvent):len((*c.CallOptions).CreateConversionEvent)], opts...) - var resp *adminpb.ConversionEvent - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.CreateConversionEvent(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.ConversionEvent{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) GetConversionEvent(ctx context.Context, req *adminpb.GetConversionEventRequest, opts ...gax.CallOption) (*adminpb.ConversionEvent, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// GetConversionEvent retrieve a single conversion event. +func (c *analyticsAdminRESTClient) GetConversionEvent(ctx context.Context, req *adminpb.GetConversionEventRequest, opts ...gax.CallOption) (*adminpb.ConversionEvent, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).GetConversionEvent[0:len((*c.CallOptions).GetConversionEvent):len((*c.CallOptions).GetConversionEvent)], opts...) - var resp *adminpb.ConversionEvent - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetConversionEvent(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.ConversionEvent{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) DeleteConversionEvent(ctx context.Context, req *adminpb.DeleteConversionEventRequest, opts ...gax.CallOption) error { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// DeleteConversionEvent deletes a conversion event in a property. +func (c *analyticsAdminRESTClient) DeleteConversionEvent(ctx context.Context, req *adminpb.DeleteConversionEventRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).DeleteConversionEvent[0:len((*c.CallOptions).DeleteConversionEvent):len((*c.CallOptions).DeleteConversionEvent)], opts...) - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - _, err = c.analyticsAdminClient.DeleteConversionEvent(ctx, req, settings.GRPC...) - return err + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) }, opts...) - return err } -func (c *analyticsAdminGRPCClient) ListConversionEvents(ctx context.Context, req *adminpb.ListConversionEventsRequest, opts ...gax.CallOption) *ConversionEventIterator { - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).ListConversionEvents[0:len((*c.CallOptions).ListConversionEvents):len((*c.CallOptions).ListConversionEvents)], opts...) +// ListConversionEvents returns a list of conversion events in the specified parent property. +// +// Returns an empty list if no conversion events are found. +func (c *analyticsAdminRESTClient) ListConversionEvents(ctx context.Context, req *adminpb.ListConversionEventsRequest, opts ...gax.CallOption) *ConversionEventIterator { it := &ConversionEventIterator{} req = proto.Clone(req).(*adminpb.ListConversionEventsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.ConversionEvent, string, error) { resp := &adminpb.ListConversionEventsResponse{} if pageToken != "" { @@ -2707,18 +6941,62 @@ func (c *analyticsAdminGRPCClient) ListConversionEvents(ctx context.Context, req } else if pageSize != 0 { req.PageSize = int32(pageSize) } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ListConversionEvents(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, "", err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/conversionEvents", req.GetParent()) + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } it.Response = resp return resp.GetConversionEvents(), resp.GetNextPageToken(), nil } + fetch := func(pageSize int, pageToken string) (string, error) { items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) if err != nil { @@ -2735,35 +7013,64 @@ func (c *analyticsAdminGRPCClient) ListConversionEvents(ctx context.Context, req return it } -func (c *analyticsAdminGRPCClient) GetDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.GetDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// GetDisplayVideo360AdvertiserLink look up a single DisplayVideo360AdvertiserLink +func (c *analyticsAdminRESTClient) GetDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.GetDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).GetDisplayVideo360AdvertiserLink[0:len((*c.CallOptions).GetDisplayVideo360AdvertiserLink):len((*c.CallOptions).GetDisplayVideo360AdvertiserLink)], opts...) - var resp *adminpb.DisplayVideo360AdvertiserLink - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetDisplayVideo360AdvertiserLink(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.DisplayVideo360AdvertiserLink{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) ListDisplayVideo360AdvertiserLinks(ctx context.Context, req *adminpb.ListDisplayVideo360AdvertiserLinksRequest, opts ...gax.CallOption) *DisplayVideo360AdvertiserLinkIterator { - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).ListDisplayVideo360AdvertiserLinks[0:len((*c.CallOptions).ListDisplayVideo360AdvertiserLinks):len((*c.CallOptions).ListDisplayVideo360AdvertiserLinks)], opts...) +// ListDisplayVideo360AdvertiserLinks lists all DisplayVideo360AdvertiserLinks on a property. +func (c *analyticsAdminRESTClient) ListDisplayVideo360AdvertiserLinks(ctx context.Context, req *adminpb.ListDisplayVideo360AdvertiserLinksRequest, opts ...gax.CallOption) *DisplayVideo360AdvertiserLinkIterator { it := &DisplayVideo360AdvertiserLinkIterator{} req = proto.Clone(req).(*adminpb.ListDisplayVideo360AdvertiserLinksRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.DisplayVideo360AdvertiserLink, string, error) { resp := &adminpb.ListDisplayVideo360AdvertiserLinksResponse{} if pageToken != "" { @@ -2774,18 +7081,62 @@ func (c *analyticsAdminGRPCClient) ListDisplayVideo360AdvertiserLinks(ctx contex } else if pageSize != 0 { req.PageSize = int32(pageSize) } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ListDisplayVideo360AdvertiserLinks(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, "", err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/displayVideo360AdvertiserLinks", req.GetParent()) + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } it.Response = resp return resp.GetDisplayVideo_360AdvertiserLinks(), resp.GetNextPageToken(), nil } + fetch := func(pageSize int, pageToken string) (string, error) { items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) if err != nil { @@ -2802,97 +7153,230 @@ func (c *analyticsAdminGRPCClient) ListDisplayVideo360AdvertiserLinks(ctx contex return it } -func (c *analyticsAdminGRPCClient) CreateDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.CreateDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// CreateDisplayVideo360AdvertiserLink creates a DisplayVideo360AdvertiserLink. +// This can only be utilized by users who have proper authorization both on +// the Google Analytics property and on the Display & Video 360 advertiser. +// Users who do not have access to the Display & Video 360 advertiser should +// instead seek to create a DisplayVideo360LinkProposal. +func (c *analyticsAdminRESTClient) CreateDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.CreateDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetDisplayVideo_360AdvertiserLink() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/displayVideo360AdvertiserLinks", req.GetParent()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).CreateDisplayVideo360AdvertiserLink[0:len((*c.CallOptions).CreateDisplayVideo360AdvertiserLink):len((*c.CallOptions).CreateDisplayVideo360AdvertiserLink)], opts...) - var resp *adminpb.DisplayVideo360AdvertiserLink - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.CreateDisplayVideo360AdvertiserLink(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.DisplayVideo360AdvertiserLink{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) DeleteDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.DeleteDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) error { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// DeleteDisplayVideo360AdvertiserLink deletes a DisplayVideo360AdvertiserLink on a property. +func (c *analyticsAdminRESTClient) DeleteDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.DeleteDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).DeleteDisplayVideo360AdvertiserLink[0:len((*c.CallOptions).DeleteDisplayVideo360AdvertiserLink):len((*c.CallOptions).DeleteDisplayVideo360AdvertiserLink)], opts...) - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - _, err = c.analyticsAdminClient.DeleteDisplayVideo360AdvertiserLink(ctx, req, settings.GRPC...) - return err + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) }, opts...) - return err } -func (c *analyticsAdminGRPCClient) UpdateDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.UpdateDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// UpdateDisplayVideo360AdvertiserLink updates a DisplayVideo360AdvertiserLink on a property. +func (c *analyticsAdminRESTClient) UpdateDisplayVideo360AdvertiserLink(ctx context.Context, req *adminpb.UpdateDisplayVideo360AdvertiserLinkRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLink, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetDisplayVideo_360AdvertiserLink() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "display_video_360_advertiser_link.name", url.QueryEscape(req.GetDisplayVideo_360AdvertiserLink().GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).UpdateDisplayVideo360AdvertiserLink[0:len((*c.CallOptions).UpdateDisplayVideo360AdvertiserLink):len((*c.CallOptions).UpdateDisplayVideo360AdvertiserLink)], opts...) - var resp *adminpb.DisplayVideo360AdvertiserLink - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.UpdateDisplayVideo360AdvertiserLink(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, err } - return resp, nil -} + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetDisplayVideo_360AdvertiserLink().GetName()) -func (c *analyticsAdminGRPCClient) GetDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.GetDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "display_video_360_advertiser_link.name", url.QueryEscape(req.GetDisplayVideo_360AdvertiserLink().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateDisplayVideo360AdvertiserLink[0:len((*c.CallOptions).UpdateDisplayVideo360AdvertiserLink):len((*c.CallOptions).UpdateDisplayVideo360AdvertiserLink)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.DisplayVideo360AdvertiserLink{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetDisplayVideo360AdvertiserLinkProposal lookup for a single DisplayVideo360AdvertiserLinkProposal. +func (c *analyticsAdminRESTClient) GetDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.GetDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).GetDisplayVideo360AdvertiserLinkProposal[0:len((*c.CallOptions).GetDisplayVideo360AdvertiserLinkProposal):len((*c.CallOptions).GetDisplayVideo360AdvertiserLinkProposal)], opts...) - var resp *adminpb.DisplayVideo360AdvertiserLinkProposal - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetDisplayVideo360AdvertiserLinkProposal(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.DisplayVideo360AdvertiserLinkProposal{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) ListDisplayVideo360AdvertiserLinkProposals(ctx context.Context, req *adminpb.ListDisplayVideo360AdvertiserLinkProposalsRequest, opts ...gax.CallOption) *DisplayVideo360AdvertiserLinkProposalIterator { - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).ListDisplayVideo360AdvertiserLinkProposals[0:len((*c.CallOptions).ListDisplayVideo360AdvertiserLinkProposals):len((*c.CallOptions).ListDisplayVideo360AdvertiserLinkProposals)], opts...) +// ListDisplayVideo360AdvertiserLinkProposals lists DisplayVideo360AdvertiserLinkProposals on a property. +func (c *analyticsAdminRESTClient) ListDisplayVideo360AdvertiserLinkProposals(ctx context.Context, req *adminpb.ListDisplayVideo360AdvertiserLinkProposalsRequest, opts ...gax.CallOption) *DisplayVideo360AdvertiserLinkProposalIterator { it := &DisplayVideo360AdvertiserLinkProposalIterator{} req = proto.Clone(req).(*adminpb.ListDisplayVideo360AdvertiserLinkProposalsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.DisplayVideo360AdvertiserLinkProposal, string, error) { resp := &adminpb.ListDisplayVideo360AdvertiserLinkProposalsResponse{} if pageToken != "" { @@ -2903,18 +7387,62 @@ func (c *analyticsAdminGRPCClient) ListDisplayVideo360AdvertiserLinkProposals(ct } else if pageSize != 0 { req.PageSize = int32(pageSize) } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ListDisplayVideo360AdvertiserLinkProposals(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, "", err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/displayVideo360AdvertiserLinkProposals", req.GetParent()) + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } it.Response = resp return resp.GetDisplayVideo_360AdvertiserLinkProposals(), resp.GetNextPageToken(), nil } + fetch := func(pageSize int, pageToken string) (string, error) { items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) if err != nil { @@ -2931,141 +7459,360 @@ func (c *analyticsAdminGRPCClient) ListDisplayVideo360AdvertiserLinkProposals(ct return it } -func (c *analyticsAdminGRPCClient) CreateDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.CreateDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// CreateDisplayVideo360AdvertiserLinkProposal creates a DisplayVideo360AdvertiserLinkProposal. +func (c *analyticsAdminRESTClient) CreateDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.CreateDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetDisplayVideo_360AdvertiserLinkProposal() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/displayVideo360AdvertiserLinkProposals", req.GetParent()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).CreateDisplayVideo360AdvertiserLinkProposal[0:len((*c.CallOptions).CreateDisplayVideo360AdvertiserLinkProposal):len((*c.CallOptions).CreateDisplayVideo360AdvertiserLinkProposal)], opts...) - var resp *adminpb.DisplayVideo360AdvertiserLinkProposal - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.CreateDisplayVideo360AdvertiserLinkProposal(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.DisplayVideo360AdvertiserLinkProposal{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) DeleteDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.DeleteDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) error { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// DeleteDisplayVideo360AdvertiserLinkProposal deletes a DisplayVideo360AdvertiserLinkProposal on a property. +// This can only be used on cancelled proposals. +func (c *analyticsAdminRESTClient) DeleteDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.DeleteDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).DeleteDisplayVideo360AdvertiserLinkProposal[0:len((*c.CallOptions).DeleteDisplayVideo360AdvertiserLinkProposal):len((*c.CallOptions).DeleteDisplayVideo360AdvertiserLinkProposal)], opts...) - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - _, err = c.analyticsAdminClient.DeleteDisplayVideo360AdvertiserLinkProposal(ctx, req, settings.GRPC...) - return err + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) }, opts...) - return err } -func (c *analyticsAdminGRPCClient) ApproveDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.ApproveDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.ApproveDisplayVideo360AdvertiserLinkProposalResponse, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// ApproveDisplayVideo360AdvertiserLinkProposal approves a DisplayVideo360AdvertiserLinkProposal. +// The DisplayVideo360AdvertiserLinkProposal will be deleted and a new +// DisplayVideo360AdvertiserLink will be created. +func (c *analyticsAdminRESTClient) ApproveDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.ApproveDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.ApproveDisplayVideo360AdvertiserLinkProposalResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v:approve", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).ApproveDisplayVideo360AdvertiserLinkProposal[0:len((*c.CallOptions).ApproveDisplayVideo360AdvertiserLinkProposal):len((*c.CallOptions).ApproveDisplayVideo360AdvertiserLinkProposal)], opts...) - var resp *adminpb.ApproveDisplayVideo360AdvertiserLinkProposalResponse - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ApproveDisplayVideo360AdvertiserLinkProposal(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.ApproveDisplayVideo360AdvertiserLinkProposalResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) CancelDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.CancelDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// CancelDisplayVideo360AdvertiserLinkProposal cancels a DisplayVideo360AdvertiserLinkProposal. +// Cancelling can mean either: +// +// Declining a proposal initiated from Display & Video 360 +// +// Withdrawing a proposal initiated from Google Analytics +// After being cancelled, a proposal will eventually be deleted automatically. +func (c *analyticsAdminRESTClient) CancelDisplayVideo360AdvertiserLinkProposal(ctx context.Context, req *adminpb.CancelDisplayVideo360AdvertiserLinkProposalRequest, opts ...gax.CallOption) (*adminpb.DisplayVideo360AdvertiserLinkProposal, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).CancelDisplayVideo360AdvertiserLinkProposal[0:len((*c.CallOptions).CancelDisplayVideo360AdvertiserLinkProposal):len((*c.CallOptions).CancelDisplayVideo360AdvertiserLinkProposal)], opts...) - var resp *adminpb.DisplayVideo360AdvertiserLinkProposal - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.CancelDisplayVideo360AdvertiserLinkProposal(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.DisplayVideo360AdvertiserLinkProposal{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) CreateCustomDimension(ctx context.Context, req *adminpb.CreateCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// CreateCustomDimension creates a CustomDimension. +func (c *analyticsAdminRESTClient) CreateCustomDimension(ctx context.Context, req *adminpb.CreateCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetCustomDimension() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/customDimensions", req.GetParent()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).CreateCustomDimension[0:len((*c.CallOptions).CreateCustomDimension):len((*c.CallOptions).CreateCustomDimension)], opts...) - var resp *adminpb.CustomDimension - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.CreateCustomDimension(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.CustomDimension{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) UpdateCustomDimension(ctx context.Context, req *adminpb.UpdateCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// UpdateCustomDimension updates a CustomDimension on a property. +func (c *analyticsAdminRESTClient) UpdateCustomDimension(ctx context.Context, req *adminpb.UpdateCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetCustomDimension() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetCustomDimension().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "custom_dimension.name", url.QueryEscape(req.GetCustomDimension().GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).UpdateCustomDimension[0:len((*c.CallOptions).UpdateCustomDimension):len((*c.CallOptions).UpdateCustomDimension)], opts...) - var resp *adminpb.CustomDimension - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.UpdateCustomDimension(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.CustomDimension{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) ListCustomDimensions(ctx context.Context, req *adminpb.ListCustomDimensionsRequest, opts ...gax.CallOption) *CustomDimensionIterator { - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).ListCustomDimensions[0:len((*c.CallOptions).ListCustomDimensions):len((*c.CallOptions).ListCustomDimensions)], opts...) +// ListCustomDimensions lists CustomDimensions on a property. +func (c *analyticsAdminRESTClient) ListCustomDimensions(ctx context.Context, req *adminpb.ListCustomDimensionsRequest, opts ...gax.CallOption) *CustomDimensionIterator { it := &CustomDimensionIterator{} req = proto.Clone(req).(*adminpb.ListCustomDimensionsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.CustomDimension, string, error) { resp := &adminpb.ListCustomDimensionsResponse{} if pageToken != "" { @@ -3076,18 +7823,62 @@ func (c *analyticsAdminGRPCClient) ListCustomDimensions(ctx context.Context, req } else if pageSize != 0 { req.PageSize = int32(pageSize) } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ListCustomDimensions(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, "", err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/customDimensions", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } it.Response = resp return resp.GetCustomDimensions(), resp.GetNextPageToken(), nil } + fetch := func(pageSize int, pageToken string) (string, error) { items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) if err != nil { @@ -3104,97 +7895,232 @@ func (c *analyticsAdminGRPCClient) ListCustomDimensions(ctx context.Context, req return it } -func (c *analyticsAdminGRPCClient) ArchiveCustomDimension(ctx context.Context, req *adminpb.ArchiveCustomDimensionRequest, opts ...gax.CallOption) error { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// ArchiveCustomDimension archives a CustomDimension on a property. +func (c *analyticsAdminRESTClient) ArchiveCustomDimension(ctx context.Context, req *adminpb.ArchiveCustomDimensionRequest, opts ...gax.CallOption) error { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return err } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).ArchiveCustomDimension[0:len((*c.CallOptions).ArchiveCustomDimension):len((*c.CallOptions).ArchiveCustomDimension)], opts...) - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - _, err = c.analyticsAdminClient.ArchiveCustomDimension(ctx, req, settings.GRPC...) + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v:archive", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) }, opts...) - return err } -func (c *analyticsAdminGRPCClient) GetCustomDimension(ctx context.Context, req *adminpb.GetCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// GetCustomDimension lookup for a single CustomDimension. +func (c *analyticsAdminRESTClient) GetCustomDimension(ctx context.Context, req *adminpb.GetCustomDimensionRequest, opts ...gax.CallOption) (*adminpb.CustomDimension, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).GetCustomDimension[0:len((*c.CallOptions).GetCustomDimension):len((*c.CallOptions).GetCustomDimension)], opts...) - var resp *adminpb.CustomDimension - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetCustomDimension(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.CustomDimension{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) CreateCustomMetric(ctx context.Context, req *adminpb.CreateCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// CreateCustomMetric creates a CustomMetric. +func (c *analyticsAdminRESTClient) CreateCustomMetric(ctx context.Context, req *adminpb.CreateCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetCustomMetric() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/customMetrics", req.GetParent()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).CreateCustomMetric[0:len((*c.CallOptions).CreateCustomMetric):len((*c.CallOptions).CreateCustomMetric)], opts...) - var resp *adminpb.CustomMetric - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.CreateCustomMetric(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.CustomMetric{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) UpdateCustomMetric(ctx context.Context, req *adminpb.UpdateCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// UpdateCustomMetric updates a CustomMetric on a property. +func (c *analyticsAdminRESTClient) UpdateCustomMetric(ctx context.Context, req *adminpb.UpdateCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetCustomMetric() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetCustomMetric().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "custom_metric.name", url.QueryEscape(req.GetCustomMetric().GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).UpdateCustomMetric[0:len((*c.CallOptions).UpdateCustomMetric):len((*c.CallOptions).UpdateCustomMetric)], opts...) - var resp *adminpb.CustomMetric - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.UpdateCustomMetric(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.CustomMetric{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) ListCustomMetrics(ctx context.Context, req *adminpb.ListCustomMetricsRequest, opts ...gax.CallOption) *CustomMetricIterator { - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).ListCustomMetrics[0:len((*c.CallOptions).ListCustomMetrics):len((*c.CallOptions).ListCustomMetrics)], opts...) +// ListCustomMetrics lists CustomMetrics on a property. +func (c *analyticsAdminRESTClient) ListCustomMetrics(ctx context.Context, req *adminpb.ListCustomMetricsRequest, opts ...gax.CallOption) *CustomMetricIterator { it := &CustomMetricIterator{} req = proto.Clone(req).(*adminpb.ListCustomMetricsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.CustomMetric, string, error) { resp := &adminpb.ListCustomMetricsResponse{} if pageToken != "" { @@ -3205,18 +8131,62 @@ func (c *analyticsAdminGRPCClient) ListCustomMetrics(ctx context.Context, req *a } else if pageSize != 0 { req.PageSize = int32(pageSize) } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ListCustomMetrics(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, "", err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/customMetrics", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } it.Response = resp return resp.GetCustomMetrics(), resp.GetNextPageToken(), nil } + fetch := func(pageSize int, pageToken string) (string, error) { items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) if err != nil { @@ -3233,159 +8203,387 @@ func (c *analyticsAdminGRPCClient) ListCustomMetrics(ctx context.Context, req *a return it } -func (c *analyticsAdminGRPCClient) ArchiveCustomMetric(ctx context.Context, req *adminpb.ArchiveCustomMetricRequest, opts ...gax.CallOption) error { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// ArchiveCustomMetric archives a CustomMetric on a property. +func (c *analyticsAdminRESTClient) ArchiveCustomMetric(ctx context.Context, req *adminpb.ArchiveCustomMetricRequest, opts ...gax.CallOption) error { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v:archive", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetCustomMetric lookup for a single CustomMetric. +func (c *analyticsAdminRESTClient) GetCustomMetric(ctx context.Context, req *adminpb.GetCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).ArchiveCustomMetric[0:len((*c.CallOptions).ArchiveCustomMetric):len((*c.CallOptions).ArchiveCustomMetric)], opts...) - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - _, err = c.analyticsAdminClient.ArchiveCustomMetric(ctx, req, settings.GRPC...) - return err + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetCustomMetric[0:len((*c.CallOptions).GetCustomMetric):len((*c.CallOptions).GetCustomMetric)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.CustomMetric{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - return err + if e != nil { + return nil, e + } + return resp, nil } -func (c *analyticsAdminGRPCClient) GetCustomMetric(ctx context.Context, req *adminpb.GetCustomMetricRequest, opts ...gax.CallOption) (*adminpb.CustomMetric, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// GetDataRetentionSettings returns the singleton data retention settings for this property. +func (c *analyticsAdminRESTClient) GetDataRetentionSettings(ctx context.Context, req *adminpb.GetDataRetentionSettingsRequest, opts ...gax.CallOption) (*adminpb.DataRetentionSettings, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).GetCustomMetric[0:len((*c.CallOptions).GetCustomMetric):len((*c.CallOptions).GetCustomMetric)], opts...) - var resp *adminpb.CustomMetric - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetCustomMetric(ctx, req, settings.GRPC...) - return err + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetDataRetentionSettings[0:len((*c.CallOptions).GetDataRetentionSettings):len((*c.CallOptions).GetDataRetentionSettings)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.DataRetentionSettings{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) GetDataRetentionSettings(ctx context.Context, req *adminpb.GetDataRetentionSettingsRequest, opts ...gax.CallOption) (*adminpb.DataRetentionSettings, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// UpdateDataRetentionSettings updates the singleton data retention settings for this property. +func (c *analyticsAdminRESTClient) UpdateDataRetentionSettings(ctx context.Context, req *adminpb.UpdateDataRetentionSettingsRequest, opts ...gax.CallOption) (*adminpb.DataRetentionSettings, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetDataRetentionSettings() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err } - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).GetDataRetentionSettings[0:len((*c.CallOptions).GetDataRetentionSettings):len((*c.CallOptions).GetDataRetentionSettings)], opts...) - var resp *adminpb.DataRetentionSettings - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetDataRetentionSettings(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, err } - return resp, nil -} + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetDataRetentionSettings().GetName()) -func (c *analyticsAdminGRPCClient) UpdateDataRetentionSettings(ctx context.Context, req *adminpb.UpdateDataRetentionSettingsRequest, opts ...gax.CallOption) (*adminpb.DataRetentionSettings, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "data_retention_settings.name", url.QueryEscape(req.GetDataRetentionSettings().GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).UpdateDataRetentionSettings[0:len((*c.CallOptions).UpdateDataRetentionSettings):len((*c.CallOptions).UpdateDataRetentionSettings)], opts...) - var resp *adminpb.DataRetentionSettings - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.UpdateDataRetentionSettings(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.DataRetentionSettings{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) CreateDataStream(ctx context.Context, req *adminpb.CreateDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// CreateDataStream creates a DataStream. +func (c *analyticsAdminRESTClient) CreateDataStream(ctx context.Context, req *adminpb.CreateDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetDataStream() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/dataStreams", req.GetParent()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).CreateDataStream[0:len((*c.CallOptions).CreateDataStream):len((*c.CallOptions).CreateDataStream)], opts...) - var resp *adminpb.DataStream - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.CreateDataStream(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.DataStream{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) DeleteDataStream(ctx context.Context, req *adminpb.DeleteDataStreamRequest, opts ...gax.CallOption) error { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// DeleteDataStream deletes a DataStream on a property. +func (c *analyticsAdminRESTClient) DeleteDataStream(ctx context.Context, req *adminpb.DeleteDataStreamRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).DeleteDataStream[0:len((*c.CallOptions).DeleteDataStream):len((*c.CallOptions).DeleteDataStream)], opts...) - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - _, err = c.analyticsAdminClient.DeleteDataStream(ctx, req, settings.GRPC...) - return err + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) }, opts...) - return err } -func (c *analyticsAdminGRPCClient) UpdateDataStream(ctx context.Context, req *adminpb.UpdateDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// UpdateDataStream updates a DataStream on a property. +func (c *analyticsAdminRESTClient) UpdateDataStream(ctx context.Context, req *adminpb.UpdateDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetDataStream() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetDataStream().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "data_stream.name", url.QueryEscape(req.GetDataStream().GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).UpdateDataStream[0:len((*c.CallOptions).UpdateDataStream):len((*c.CallOptions).UpdateDataStream)], opts...) - var resp *adminpb.DataStream - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.UpdateDataStream(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.DataStream{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } -func (c *analyticsAdminGRPCClient) ListDataStreams(ctx context.Context, req *adminpb.ListDataStreamsRequest, opts ...gax.CallOption) *DataStreamIterator { - md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) - - ctx = insertMetadata(ctx, c.xGoogMetadata, md) - opts = append((*c.CallOptions).ListDataStreams[0:len((*c.CallOptions).ListDataStreams):len((*c.CallOptions).ListDataStreams)], opts...) +// ListDataStreams lists DataStreams on a property. +func (c *analyticsAdminRESTClient) ListDataStreams(ctx context.Context, req *adminpb.ListDataStreamsRequest, opts ...gax.CallOption) *DataStreamIterator { it := &DataStreamIterator{} req = proto.Clone(req).(*adminpb.ListDataStreamsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.DataStream, string, error) { resp := &adminpb.ListDataStreamsResponse{} if pageToken != "" { @@ -3396,18 +8594,62 @@ func (c *analyticsAdminGRPCClient) ListDataStreams(ctx context.Context, req *adm } else if pageSize != 0 { req.PageSize = int32(pageSize) } - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.ListDataStreams(ctx, req, settings.GRPC...) - return err - }, opts...) + baseUrl, err := url.Parse(c.endpoint) if err != nil { return nil, "", err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/dataStreams", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } it.Response = resp return resp.GetDataStreams(), resp.GetNextPageToken(), nil } + fetch := func(pageSize int, pageToken string) (string, error) { items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) if err != nil { @@ -3424,24 +8666,55 @@ func (c *analyticsAdminGRPCClient) ListDataStreams(ctx context.Context, req *adm return it } -func (c *analyticsAdminGRPCClient) GetDataStream(ctx context.Context, req *adminpb.GetDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { - if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { - cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) - defer cancel() - ctx = cctx +// GetDataStream lookup for a single DataStream. +func (c *analyticsAdminRESTClient) GetDataStream(ctx context.Context, req *adminpb.GetDataStreamRequest, opts ...gax.CallOption) (*adminpb.DataStream, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) - ctx = insertMetadata(ctx, c.xGoogMetadata, md) + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) opts = append((*c.CallOptions).GetDataStream[0:len((*c.CallOptions).GetDataStream):len((*c.CallOptions).GetDataStream)], opts...) - var resp *adminpb.DataStream - err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { - var err error - resp, err = c.analyticsAdminClient.GetDataStream(ctx, req, settings.GRPC...) - return err + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &adminpb.DataStream{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil }, opts...) - if err != nil { - return nil, err + if e != nil { + return nil, e } return resp, nil } diff --git a/analytics/admin/apiv1alpha/analytics_admin_client_example_test.go b/analytics/admin/apiv1alpha/analytics_admin_client_example_test.go index ed89b322f3b3..c5183221f6ca 100644 --- a/analytics/admin/apiv1alpha/analytics_admin_client_example_test.go +++ b/analytics/admin/apiv1alpha/analytics_admin_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewAnalyticsAdminClient() { _ = c } +func ExampleNewAnalyticsAdminRESTClient() { + ctx := context.Background() + c, err := admin.NewAnalyticsAdminRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleAnalyticsAdminClient_GetAccount() { ctx := context.Background() c, err := admin.NewAnalyticsAdminClient(ctx) diff --git a/analytics/admin/apiv1alpha/doc.go b/analytics/admin/apiv1alpha/doc.go index 0c55177283a2..f11b4c761a23 100644 --- a/analytics/admin/apiv1alpha/doc.go +++ b/analytics/admin/apiv1alpha/doc.go @@ -69,6 +69,8 @@ package admin // import "cloud.google.com/go/analytics/admin/apiv1alpha" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -160,3 +162,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/analytics/admin/apiv1alpha/gapic_metadata.json b/analytics/admin/apiv1alpha/gapic_metadata.json index 1b446bb6fc2e..2d48d9f6a985 100644 --- a/analytics/admin/apiv1alpha/gapic_metadata.json +++ b/analytics/admin/apiv1alpha/gapic_metadata.json @@ -366,6 +366,366 @@ ] } } + }, + "rest": { + "libraryClient": "AnalyticsAdminClient", + "rpcs": { + "AcknowledgeUserDataCollection": { + "methods": [ + "AcknowledgeUserDataCollection" + ] + }, + "ApproveDisplayVideo360AdvertiserLinkProposal": { + "methods": [ + "ApproveDisplayVideo360AdvertiserLinkProposal" + ] + }, + "ArchiveCustomDimension": { + "methods": [ + "ArchiveCustomDimension" + ] + }, + "ArchiveCustomMetric": { + "methods": [ + "ArchiveCustomMetric" + ] + }, + "AuditUserLinks": { + "methods": [ + "AuditUserLinks" + ] + }, + "BatchCreateUserLinks": { + "methods": [ + "BatchCreateUserLinks" + ] + }, + "BatchDeleteUserLinks": { + "methods": [ + "BatchDeleteUserLinks" + ] + }, + "BatchGetUserLinks": { + "methods": [ + "BatchGetUserLinks" + ] + }, + "BatchUpdateUserLinks": { + "methods": [ + "BatchUpdateUserLinks" + ] + }, + "CancelDisplayVideo360AdvertiserLinkProposal": { + "methods": [ + "CancelDisplayVideo360AdvertiserLinkProposal" + ] + }, + "CreateConversionEvent": { + "methods": [ + "CreateConversionEvent" + ] + }, + "CreateCustomDimension": { + "methods": [ + "CreateCustomDimension" + ] + }, + "CreateCustomMetric": { + "methods": [ + "CreateCustomMetric" + ] + }, + "CreateDataStream": { + "methods": [ + "CreateDataStream" + ] + }, + "CreateDisplayVideo360AdvertiserLink": { + "methods": [ + "CreateDisplayVideo360AdvertiserLink" + ] + }, + "CreateDisplayVideo360AdvertiserLinkProposal": { + "methods": [ + "CreateDisplayVideo360AdvertiserLinkProposal" + ] + }, + "CreateFirebaseLink": { + "methods": [ + "CreateFirebaseLink" + ] + }, + "CreateGoogleAdsLink": { + "methods": [ + "CreateGoogleAdsLink" + ] + }, + "CreateMeasurementProtocolSecret": { + "methods": [ + "CreateMeasurementProtocolSecret" + ] + }, + "CreateProperty": { + "methods": [ + "CreateProperty" + ] + }, + "CreateUserLink": { + "methods": [ + "CreateUserLink" + ] + }, + "DeleteAccount": { + "methods": [ + "DeleteAccount" + ] + }, + "DeleteConversionEvent": { + "methods": [ + "DeleteConversionEvent" + ] + }, + "DeleteDataStream": { + "methods": [ + "DeleteDataStream" + ] + }, + "DeleteDisplayVideo360AdvertiserLink": { + "methods": [ + "DeleteDisplayVideo360AdvertiserLink" + ] + }, + "DeleteDisplayVideo360AdvertiserLinkProposal": { + "methods": [ + "DeleteDisplayVideo360AdvertiserLinkProposal" + ] + }, + "DeleteFirebaseLink": { + "methods": [ + "DeleteFirebaseLink" + ] + }, + "DeleteGoogleAdsLink": { + "methods": [ + "DeleteGoogleAdsLink" + ] + }, + "DeleteMeasurementProtocolSecret": { + "methods": [ + "DeleteMeasurementProtocolSecret" + ] + }, + "DeleteProperty": { + "methods": [ + "DeleteProperty" + ] + }, + "DeleteUserLink": { + "methods": [ + "DeleteUserLink" + ] + }, + "GetAccount": { + "methods": [ + "GetAccount" + ] + }, + "GetConversionEvent": { + "methods": [ + "GetConversionEvent" + ] + }, + "GetCustomDimension": { + "methods": [ + "GetCustomDimension" + ] + }, + "GetCustomMetric": { + "methods": [ + "GetCustomMetric" + ] + }, + "GetDataRetentionSettings": { + "methods": [ + "GetDataRetentionSettings" + ] + }, + "GetDataSharingSettings": { + "methods": [ + "GetDataSharingSettings" + ] + }, + "GetDataStream": { + "methods": [ + "GetDataStream" + ] + }, + "GetDisplayVideo360AdvertiserLink": { + "methods": [ + "GetDisplayVideo360AdvertiserLink" + ] + }, + "GetDisplayVideo360AdvertiserLinkProposal": { + "methods": [ + "GetDisplayVideo360AdvertiserLinkProposal" + ] + }, + "GetGlobalSiteTag": { + "methods": [ + "GetGlobalSiteTag" + ] + }, + "GetGoogleSignalsSettings": { + "methods": [ + "GetGoogleSignalsSettings" + ] + }, + "GetMeasurementProtocolSecret": { + "methods": [ + "GetMeasurementProtocolSecret" + ] + }, + "GetProperty": { + "methods": [ + "GetProperty" + ] + }, + "GetUserLink": { + "methods": [ + "GetUserLink" + ] + }, + "ListAccountSummaries": { + "methods": [ + "ListAccountSummaries" + ] + }, + "ListAccounts": { + "methods": [ + "ListAccounts" + ] + }, + "ListConversionEvents": { + "methods": [ + "ListConversionEvents" + ] + }, + "ListCustomDimensions": { + "methods": [ + "ListCustomDimensions" + ] + }, + "ListCustomMetrics": { + "methods": [ + "ListCustomMetrics" + ] + }, + "ListDataStreams": { + "methods": [ + "ListDataStreams" + ] + }, + "ListDisplayVideo360AdvertiserLinkProposals": { + "methods": [ + "ListDisplayVideo360AdvertiserLinkProposals" + ] + }, + "ListDisplayVideo360AdvertiserLinks": { + "methods": [ + "ListDisplayVideo360AdvertiserLinks" + ] + }, + "ListFirebaseLinks": { + "methods": [ + "ListFirebaseLinks" + ] + }, + "ListGoogleAdsLinks": { + "methods": [ + "ListGoogleAdsLinks" + ] + }, + "ListMeasurementProtocolSecrets": { + "methods": [ + "ListMeasurementProtocolSecrets" + ] + }, + "ListProperties": { + "methods": [ + "ListProperties" + ] + }, + "ListUserLinks": { + "methods": [ + "ListUserLinks" + ] + }, + "ProvisionAccountTicket": { + "methods": [ + "ProvisionAccountTicket" + ] + }, + "SearchChangeHistoryEvents": { + "methods": [ + "SearchChangeHistoryEvents" + ] + }, + "UpdateAccount": { + "methods": [ + "UpdateAccount" + ] + }, + "UpdateCustomDimension": { + "methods": [ + "UpdateCustomDimension" + ] + }, + "UpdateCustomMetric": { + "methods": [ + "UpdateCustomMetric" + ] + }, + "UpdateDataRetentionSettings": { + "methods": [ + "UpdateDataRetentionSettings" + ] + }, + "UpdateDataStream": { + "methods": [ + "UpdateDataStream" + ] + }, + "UpdateDisplayVideo360AdvertiserLink": { + "methods": [ + "UpdateDisplayVideo360AdvertiserLink" + ] + }, + "UpdateGoogleAdsLink": { + "methods": [ + "UpdateGoogleAdsLink" + ] + }, + "UpdateGoogleSignalsSettings": { + "methods": [ + "UpdateGoogleSignalsSettings" + ] + }, + "UpdateMeasurementProtocolSecret": { + "methods": [ + "UpdateMeasurementProtocolSecret" + ] + }, + "UpdateProperty": { + "methods": [ + "UpdateProperty" + ] + }, + "UpdateUserLink": { + "methods": [ + "UpdateUserLink" + ] + } + } } } } diff --git a/area120/tables/apiv1alpha1/doc.go b/area120/tables/apiv1alpha1/doc.go index 757571bd6405..3f852c638aa7 100644 --- a/area120/tables/apiv1alpha1/doc.go +++ b/area120/tables/apiv1alpha1/doc.go @@ -69,6 +69,8 @@ package tables // import "cloud.google.com/go/area120/tables/apiv1alpha1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -162,3 +164,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/area120/tables/apiv1alpha1/gapic_metadata.json b/area120/tables/apiv1alpha1/gapic_metadata.json index 5e6200fc68e3..be473ff7d191 100644 --- a/area120/tables/apiv1alpha1/gapic_metadata.json +++ b/area120/tables/apiv1alpha1/gapic_metadata.json @@ -71,6 +71,71 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "BatchCreateRows": { + "methods": [ + "BatchCreateRows" + ] + }, + "BatchDeleteRows": { + "methods": [ + "BatchDeleteRows" + ] + }, + "BatchUpdateRows": { + "methods": [ + "BatchUpdateRows" + ] + }, + "CreateRow": { + "methods": [ + "CreateRow" + ] + }, + "DeleteRow": { + "methods": [ + "DeleteRow" + ] + }, + "GetRow": { + "methods": [ + "GetRow" + ] + }, + "GetTable": { + "methods": [ + "GetTable" + ] + }, + "GetWorkspace": { + "methods": [ + "GetWorkspace" + ] + }, + "ListRows": { + "methods": [ + "ListRows" + ] + }, + "ListTables": { + "methods": [ + "ListTables" + ] + }, + "ListWorkspaces": { + "methods": [ + "ListWorkspaces" + ] + }, + "UpdateRow": { + "methods": [ + "UpdateRow" + ] + } + } } } } diff --git a/area120/tables/apiv1alpha1/tables_client.go b/area120/tables/apiv1alpha1/tables_client.go index 25cd46dce482..b8f457c9006c 100644 --- a/area120/tables/apiv1alpha1/tables_client.go +++ b/area120/tables/apiv1alpha1/tables_client.go @@ -17,20 +17,26 @@ package tables import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" tablespb "google.golang.org/genproto/googleapis/area120/tables/v1alpha1" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -81,6 +87,23 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + GetTable: []gax.CallOption{}, + ListTables: []gax.CallOption{}, + GetWorkspace: []gax.CallOption{}, + ListWorkspaces: []gax.CallOption{}, + GetRow: []gax.CallOption{}, + ListRows: []gax.CallOption{}, + CreateRow: []gax.CallOption{}, + BatchCreateRows: []gax.CallOption{}, + UpdateRow: []gax.CallOption{}, + BatchUpdateRows: []gax.CallOption{}, + DeleteRow: []gax.CallOption{}, + BatchDeleteRows: []gax.CallOption{}, + } +} + // internalClient is an interface that defines the methods available from Area120 Tables API. type internalClient interface { Close() error @@ -296,6 +319,85 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new tables service rest client. +// +// The Tables Service provides an API for reading and updating tables. +// It defines the following resource model: +// +// The API has a collection of [Table][google.area120.tables.v1alpha1.Table] +// resources, named tables/* +// +// Each Table has a collection of [Row][google.area120.tables.v1alpha1.Row] +// resources, named tables/*/rows/* +// +// The API has a collection of +// [Workspace][google.area120.tables.v1alpha1.Workspace] +// resources, named workspaces/*. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://area120tables.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://area120tables.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://area120tables.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) GetTable(ctx context.Context, req *tablespb.GetTableRequest, opts ...gax.CallOption) (*tablespb.Table, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -617,6 +719,770 @@ func (c *gRPCClient) BatchDeleteRows(ctx context.Context, req *tablespb.BatchDel return err } +// GetTable gets a table. Returns NOT_FOUND if the table does not exist. +func (c *restClient) GetTable(ctx context.Context, req *tablespb.GetTableRequest, opts ...gax.CallOption) (*tablespb.Table, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetTable[0:len((*c.CallOptions).GetTable):len((*c.CallOptions).GetTable)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &tablespb.Table{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListTables lists tables for the user. +func (c *restClient) ListTables(ctx context.Context, req *tablespb.ListTablesRequest, opts ...gax.CallOption) *TableIterator { + it := &TableIterator{} + req = proto.Clone(req).(*tablespb.ListTablesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*tablespb.Table, string, error) { + resp := &tablespb.ListTablesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/tables") + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetTables(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetWorkspace gets a workspace. Returns NOT_FOUND if the workspace does not exist. +func (c *restClient) GetWorkspace(ctx context.Context, req *tablespb.GetWorkspaceRequest, opts ...gax.CallOption) (*tablespb.Workspace, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetWorkspace[0:len((*c.CallOptions).GetWorkspace):len((*c.CallOptions).GetWorkspace)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &tablespb.Workspace{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListWorkspaces lists workspaces for the user. +func (c *restClient) ListWorkspaces(ctx context.Context, req *tablespb.ListWorkspacesRequest, opts ...gax.CallOption) *WorkspaceIterator { + it := &WorkspaceIterator{} + req = proto.Clone(req).(*tablespb.ListWorkspacesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*tablespb.Workspace, string, error) { + resp := &tablespb.ListWorkspacesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/workspaces") + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetWorkspaces(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetRow gets a row. Returns NOT_FOUND if the row does not exist in the table. +func (c *restClient) GetRow(ctx context.Context, req *tablespb.GetRowRequest, opts ...gax.CallOption) (*tablespb.Row, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetName()) + + params := url.Values{} + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetRow[0:len((*c.CallOptions).GetRow):len((*c.CallOptions).GetRow)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &tablespb.Row{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListRows lists rows in a table. Returns NOT_FOUND if the table does not exist. +func (c *restClient) ListRows(ctx context.Context, req *tablespb.ListRowsRequest, opts ...gax.CallOption) *RowIterator { + it := &RowIterator{} + req = proto.Clone(req).(*tablespb.ListRowsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*tablespb.Row, string, error) { + resp := &tablespb.ListRowsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/rows", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetRows(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CreateRow creates a row. +func (c *restClient) CreateRow(ctx context.Context, req *tablespb.CreateRowRequest, opts ...gax.CallOption) (*tablespb.Row, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetRow() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/rows", req.GetParent()) + + params := url.Values{} + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateRow[0:len((*c.CallOptions).CreateRow):len((*c.CallOptions).CreateRow)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &tablespb.Row{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// BatchCreateRows creates multiple rows. +func (c *restClient) BatchCreateRows(ctx context.Context, req *tablespb.BatchCreateRowsRequest, opts ...gax.CallOption) (*tablespb.BatchCreateRowsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/rows:batchCreate", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).BatchCreateRows[0:len((*c.CallOptions).BatchCreateRows):len((*c.CallOptions).BatchCreateRows)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &tablespb.BatchCreateRowsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateRow updates a row. +func (c *restClient) UpdateRow(ctx context.Context, req *tablespb.UpdateRowRequest, opts ...gax.CallOption) (*tablespb.Row, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetRow() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetRow().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "row.name", url.QueryEscape(req.GetRow().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateRow[0:len((*c.CallOptions).UpdateRow):len((*c.CallOptions).UpdateRow)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &tablespb.Row{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// BatchUpdateRows updates multiple rows. +func (c *restClient) BatchUpdateRows(ctx context.Context, req *tablespb.BatchUpdateRowsRequest, opts ...gax.CallOption) (*tablespb.BatchUpdateRowsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/rows:batchUpdate", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).BatchUpdateRows[0:len((*c.CallOptions).BatchUpdateRows):len((*c.CallOptions).BatchUpdateRows)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &tablespb.BatchUpdateRowsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteRow deletes a row. +func (c *restClient) DeleteRow(ctx context.Context, req *tablespb.DeleteRowRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// BatchDeleteRows deletes multiple rows. +func (c *restClient) BatchDeleteRows(ctx context.Context, req *tablespb.BatchDeleteRowsRequest, opts ...gax.CallOption) error { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/rows:batchDelete", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + // RowIterator manages a stream of *tablespb.Row. type RowIterator struct { items []*tablespb.Row diff --git a/area120/tables/apiv1alpha1/tables_client_example_test.go b/area120/tables/apiv1alpha1/tables_client_example_test.go index edf80cf13964..b81b87eb8d23 100644 --- a/area120/tables/apiv1alpha1/tables_client_example_test.go +++ b/area120/tables/apiv1alpha1/tables_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := tables.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_GetTable() { ctx := context.Background() c, err := tables.NewClient(ctx) diff --git a/asset/apiv1p2beta1/asset_client.go b/asset/apiv1p2beta1/asset_client.go index 3712aaca2282..20da0e89af6d 100644 --- a/asset/apiv1p2beta1/asset_client.go +++ b/asset/apiv1p2beta1/asset_client.go @@ -17,20 +17,26 @@ package asset import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" assetpb "google.golang.org/genproto/googleapis/cloud/asset/v1p2beta1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newClientHook clientHook @@ -99,6 +105,46 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + CreateFeed: []gax.CallOption{}, + GetFeed: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + ListFeeds: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + UpdateFeed: []gax.CallOption{}, + DeleteFeed: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + } +} + // internalClient is an interface that defines the methods available from Cloud Asset API. type internalClient interface { Close() error @@ -251,6 +297,74 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new asset service rest client. +// +// Asset service definition. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://cloudasset.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://cloudasset.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://cloudasset.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) CreateFeed(ctx context.Context, req *assetpb.CreateFeedRequest, opts ...gax.CallOption) (*assetpb.Feed, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -356,3 +470,263 @@ func (c *gRPCClient) DeleteFeed(ctx context.Context, req *assetpb.DeleteFeedRequ }, opts...) return err } + +// CreateFeed creates a feed in a parent project/folder/organization to listen to its +// asset updates. +func (c *restClient) CreateFeed(ctx context.Context, req *assetpb.CreateFeedRequest, opts ...gax.CallOption) (*assetpb.Feed, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1p2beta1/%v/feeds", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateFeed[0:len((*c.CallOptions).CreateFeed):len((*c.CallOptions).CreateFeed)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &assetpb.Feed{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetFeed gets details about an asset feed. +func (c *restClient) GetFeed(ctx context.Context, req *assetpb.GetFeedRequest, opts ...gax.CallOption) (*assetpb.Feed, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1p2beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetFeed[0:len((*c.CallOptions).GetFeed):len((*c.CallOptions).GetFeed)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &assetpb.Feed{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListFeeds lists all asset feeds in a parent project/folder/organization. +func (c *restClient) ListFeeds(ctx context.Context, req *assetpb.ListFeedsRequest, opts ...gax.CallOption) (*assetpb.ListFeedsResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1p2beta1/%v/feeds", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ListFeeds[0:len((*c.CallOptions).ListFeeds):len((*c.CallOptions).ListFeeds)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &assetpb.ListFeedsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateFeed updates an asset feed configuration. +func (c *restClient) UpdateFeed(ctx context.Context, req *assetpb.UpdateFeedRequest, opts ...gax.CallOption) (*assetpb.Feed, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1p2beta1/%v", req.GetFeed().GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "feed.name", url.QueryEscape(req.GetFeed().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateFeed[0:len((*c.CallOptions).UpdateFeed):len((*c.CallOptions).UpdateFeed)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &assetpb.Feed{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteFeed deletes an asset feed. +func (c *restClient) DeleteFeed(ctx context.Context, req *assetpb.DeleteFeedRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1p2beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} diff --git a/asset/apiv1p2beta1/asset_client_example_test.go b/asset/apiv1p2beta1/asset_client_example_test.go index d418a5bf782d..69426fb2a61d 100644 --- a/asset/apiv1p2beta1/asset_client_example_test.go +++ b/asset/apiv1p2beta1/asset_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := asset.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_CreateFeed() { ctx := context.Background() c, err := asset.NewClient(ctx) diff --git a/asset/apiv1p2beta1/doc.go b/asset/apiv1p2beta1/doc.go index 4fcce49ca291..b481cc8d3a32 100644 --- a/asset/apiv1p2beta1/doc.go +++ b/asset/apiv1p2beta1/doc.go @@ -71,6 +71,8 @@ package asset // import "cloud.google.com/go/asset/apiv1p2beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -159,3 +161,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/asset/apiv1p2beta1/gapic_metadata.json b/asset/apiv1p2beta1/gapic_metadata.json index ea91937f1006..a013883a5cb9 100644 --- a/asset/apiv1p2beta1/gapic_metadata.json +++ b/asset/apiv1p2beta1/gapic_metadata.json @@ -36,6 +36,36 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "CreateFeed": { + "methods": [ + "CreateFeed" + ] + }, + "DeleteFeed": { + "methods": [ + "DeleteFeed" + ] + }, + "GetFeed": { + "methods": [ + "GetFeed" + ] + }, + "ListFeeds": { + "methods": [ + "ListFeeds" + ] + }, + "UpdateFeed": { + "methods": [ + "UpdateFeed" + ] + } + } } } } diff --git a/asset/apiv1p5beta1/asset_client.go b/asset/apiv1p5beta1/asset_client.go index 1be8a9cdfc94..ea104b3755f2 100644 --- a/asset/apiv1p5beta1/asset_client.go +++ b/asset/apiv1p5beta1/asset_client.go @@ -19,19 +19,24 @@ package asset import ( "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" assetpb "google.golang.org/genproto/googleapis/cloud/asset/v1p5beta1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -71,6 +76,22 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + ListAssets: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + } +} + // internalClient is an interface that defines the methods available from Cloud Asset API. type internalClient interface { Close() error @@ -199,6 +220,74 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new asset service rest client. +// +// Asset service definition. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://cloudasset.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://cloudasset.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://cloudasset.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) ListAssets(ctx context.Context, req *assetpb.ListAssetsRequest, opts ...gax.CallOption) *AssetIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -244,6 +333,106 @@ func (c *gRPCClient) ListAssets(ctx context.Context, req *assetpb.ListAssetsRequ return it } +// ListAssets lists assets with time and resource types and returns paged results in +// response. +func (c *restClient) ListAssets(ctx context.Context, req *assetpb.ListAssetsRequest, opts ...gax.CallOption) *AssetIterator { + it := &AssetIterator{} + req = proto.Clone(req).(*assetpb.ListAssetsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*assetpb.Asset, string, error) { + resp := &assetpb.ListAssetsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1p5beta1/%v/assets", req.GetParent()) + + params := url.Values{} + if req.GetAssetTypes() != nil { + params.Add("assetTypes", fmt.Sprintf("%v", req.GetAssetTypes())) + } + if req.GetContentType() != 0 { + params.Add("contentType", fmt.Sprintf("%v", req.GetContentType())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetReadTime().GetNanos() != 0 { + params.Add("readTime.nanos", fmt.Sprintf("%v", req.GetReadTime().GetNanos())) + } + if req.GetReadTime().GetSeconds() != 0 { + params.Add("readTime.seconds", fmt.Sprintf("%v", req.GetReadTime().GetSeconds())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetAssets(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // AssetIterator manages a stream of *assetpb.Asset. type AssetIterator struct { items []*assetpb.Asset diff --git a/asset/apiv1p5beta1/asset_client_example_test.go b/asset/apiv1p5beta1/asset_client_example_test.go index 666d9de3bb0c..b28c5fe9b8a0 100644 --- a/asset/apiv1p5beta1/asset_client_example_test.go +++ b/asset/apiv1p5beta1/asset_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := asset.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_ListAssets() { ctx := context.Background() c, err := asset.NewClient(ctx) diff --git a/asset/apiv1p5beta1/doc.go b/asset/apiv1p5beta1/doc.go index ce1988449697..0ae7b8b98b0b 100644 --- a/asset/apiv1p5beta1/doc.go +++ b/asset/apiv1p5beta1/doc.go @@ -77,6 +77,8 @@ package asset // import "cloud.google.com/go/asset/apiv1p5beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -165,3 +167,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/asset/apiv1p5beta1/gapic_metadata.json b/asset/apiv1p5beta1/gapic_metadata.json index f8255c2a8b36..c303bc74708e 100644 --- a/asset/apiv1p5beta1/gapic_metadata.json +++ b/asset/apiv1p5beta1/gapic_metadata.json @@ -16,6 +16,16 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "ListAssets": { + "methods": [ + "ListAssets" + ] + } + } } } } diff --git a/assuredworkloads/apiv1beta1/assured_workloads_client.go b/assuredworkloads/apiv1beta1/assured_workloads_client.go index 59cba83eec22..2ebf6c9c18d1 100644 --- a/assuredworkloads/apiv1beta1/assured_workloads_client.go +++ b/assuredworkloads/apiv1beta1/assured_workloads_client.go @@ -17,24 +17,30 @@ package assuredworkloads import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" assuredworkloadspb "google.golang.org/genproto/googleapis/cloud/assuredworkloads/v1beta1" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -101,6 +107,43 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + CreateWorkload: []gax.CallOption{}, + UpdateWorkload: []gax.CallOption{}, + DeleteWorkload: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 200 * time.Millisecond, + Max: 30000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetWorkload: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 200 * time.Millisecond, + Max: 30000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListWorkloads: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 200 * time.Millisecond, + Max: 30000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + } +} + // internalClient is an interface that defines the methods available from Assured Workloads API. type internalClient interface { Close() error @@ -285,6 +328,89 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new assured workloads service rest client. +// +// Service to manage AssuredWorkloads. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://assuredworkloads.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://assuredworkloads.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://assuredworkloads.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) CreateWorkload(ctx context.Context, req *assuredworkloadspb.CreateWorkloadRequest, opts ...gax.CallOption) (*CreateWorkloadOperation, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -416,9 +542,338 @@ func (c *gRPCClient) ListWorkloads(ctx context.Context, req *assuredworkloadspb. return it } +// CreateWorkload creates Assured Workload. +func (c *restClient) CreateWorkload(ctx context.Context, req *assuredworkloadspb.CreateWorkloadRequest, opts ...gax.CallOption) (*CreateWorkloadOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetWorkload() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/workloads", req.GetParent()) + + params := url.Values{} + if req.GetExternalId() != "" { + params.Add("externalId", fmt.Sprintf("%v", req.GetExternalId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &CreateWorkloadOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UpdateWorkload updates an existing workload. +// Currently allows updating of workload display_name and labels. +// For force updates don’t set etag field in the Workload. +// Only one update operation per workload can be in progress. +func (c *restClient) UpdateWorkload(ctx context.Context, req *assuredworkloadspb.UpdateWorkloadRequest, opts ...gax.CallOption) (*assuredworkloadspb.Workload, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetWorkload() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetWorkload().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "workload.name", url.QueryEscape(req.GetWorkload().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateWorkload[0:len((*c.CallOptions).UpdateWorkload):len((*c.CallOptions).UpdateWorkload)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &assuredworkloadspb.Workload{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteWorkload deletes the workload. Make sure that workload’s direct children are already +// in a deleted state, otherwise the request will fail with a +// FAILED_PRECONDITION error. +func (c *restClient) DeleteWorkload(ctx context.Context, req *assuredworkloadspb.DeleteWorkloadRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetEtag() != "" { + params.Add("etag", fmt.Sprintf("%v", req.GetEtag())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetWorkload gets Assured Workload associated with a CRM Node +func (c *restClient) GetWorkload(ctx context.Context, req *assuredworkloadspb.GetWorkloadRequest, opts ...gax.CallOption) (*assuredworkloadspb.Workload, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetWorkload[0:len((*c.CallOptions).GetWorkload):len((*c.CallOptions).GetWorkload)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &assuredworkloadspb.Workload{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListWorkloads lists Assured Workloads under a CRM Node. +func (c *restClient) ListWorkloads(ctx context.Context, req *assuredworkloadspb.ListWorkloadsRequest, opts ...gax.CallOption) *WorkloadIterator { + it := &WorkloadIterator{} + req = proto.Clone(req).(*assuredworkloadspb.ListWorkloadsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*assuredworkloadspb.Workload, string, error) { + resp := &assuredworkloadspb.ListWorkloadsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/workloads", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetWorkloads(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // CreateWorkloadOperation manages a long-running operation from CreateWorkload. type CreateWorkloadOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // CreateWorkloadOperation returns a new CreateWorkloadOperation from a given name. @@ -429,10 +884,21 @@ func (c *gRPCClient) CreateWorkloadOperation(name string) *CreateWorkloadOperati } } +// CreateWorkloadOperation returns a new CreateWorkloadOperation from a given name. +// The name must be that of a previously created CreateWorkloadOperation, possibly from a different process. +func (c *restClient) CreateWorkloadOperation(name string) *CreateWorkloadOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &CreateWorkloadOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *CreateWorkloadOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*assuredworkloadspb.Workload, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp assuredworkloadspb.Workload if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -450,6 +916,7 @@ func (op *CreateWorkloadOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *CreateWorkloadOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*assuredworkloadspb.Workload, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp assuredworkloadspb.Workload if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/assuredworkloads/apiv1beta1/assured_workloads_client_example_test.go b/assuredworkloads/apiv1beta1/assured_workloads_client_example_test.go index 9efed65aea64..6ace5c594f94 100644 --- a/assuredworkloads/apiv1beta1/assured_workloads_client_example_test.go +++ b/assuredworkloads/apiv1beta1/assured_workloads_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := assuredworkloads.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_CreateWorkload() { ctx := context.Background() c, err := assuredworkloads.NewClient(ctx) diff --git a/assuredworkloads/apiv1beta1/doc.go b/assuredworkloads/apiv1beta1/doc.go index b7a4d35f1bac..b0d529cac149 100644 --- a/assuredworkloads/apiv1beta1/doc.go +++ b/assuredworkloads/apiv1beta1/doc.go @@ -74,6 +74,8 @@ package assuredworkloads // import "cloud.google.com/go/assuredworkloads/apiv1be import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -162,3 +164,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/assuredworkloads/apiv1beta1/gapic_metadata.json b/assuredworkloads/apiv1beta1/gapic_metadata.json index fca15a740bd1..dd0ab7e9c5a7 100644 --- a/assuredworkloads/apiv1beta1/gapic_metadata.json +++ b/assuredworkloads/apiv1beta1/gapic_metadata.json @@ -36,6 +36,36 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "CreateWorkload": { + "methods": [ + "CreateWorkload" + ] + }, + "DeleteWorkload": { + "methods": [ + "DeleteWorkload" + ] + }, + "GetWorkload": { + "methods": [ + "GetWorkload" + ] + }, + "ListWorkloads": { + "methods": [ + "ListWorkloads" + ] + }, + "UpdateWorkload": { + "methods": [ + "UpdateWorkload" + ] + } + } } } } diff --git a/automl/apiv1beta1/auto_ml_client.go b/automl/apiv1beta1/auto_ml_client.go index 42829fc7379e..94534d855881 100644 --- a/automl/apiv1beta1/auto_ml_client.go +++ b/automl/apiv1beta1/auto_ml_client.go @@ -17,24 +17,30 @@ package automl import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" automlpb "google.golang.org/genproto/googleapis/cloud/automl/v1beta1" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -241,6 +247,155 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + CreateDataset: []gax.CallOption{}, + GetDataset: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + ListDatasets: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + UpdateDataset: []gax.CallOption{}, + DeleteDataset: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + ImportData: []gax.CallOption{}, + ExportData: []gax.CallOption{}, + GetAnnotationSpec: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + GetTableSpec: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + ListTableSpecs: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + UpdateTableSpec: []gax.CallOption{}, + GetColumnSpec: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + ListColumnSpecs: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + UpdateColumnSpec: []gax.CallOption{}, + CreateModel: []gax.CallOption{}, + GetModel: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + ListModels: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + DeleteModel: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + DeployModel: []gax.CallOption{}, + UndeployModel: []gax.CallOption{}, + ExportModel: []gax.CallOption{}, + ExportEvaluatedExamples: []gax.CallOption{}, + GetModelEvaluation: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + ListModelEvaluations: []gax.CallOption{}, + } +} + // internalClient is an interface that defines the methods available from Cloud AutoML API. type internalClient interface { Close() error @@ -676,6 +831,102 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new auto ml rest client. +// +// AutoML Server API. +// +// The resource names are assigned by the server. +// The server never reuses names that it has created after the resources with +// those names are deleted. +// +// An ID of a resource is the last element of the item’s resource name. For +// projects/{project_id}/locations/{location_id}/datasets/{dataset_id}, then +// the id for the item is {dataset_id}. +// +// Currently the only supported location_id is “us-central1”. +// +// On any input that is documented to expect a string parameter in +// snake_case or kebab-case, either of those cases is accepted. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://automl.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://automl.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://automl.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) CreateDataset(ctx context.Context, req *automlpb.CreateDatasetRequest, opts ...gax.CallOption) (*automlpb.Dataset, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 5000*time.Millisecond) @@ -1337,92 +1588,1782 @@ func (c *gRPCClient) ListModelEvaluations(ctx context.Context, req *automlpb.Lis return it } -// CreateModelOperation manages a long-running operation from CreateModel. -type CreateModelOperation struct { - lro *longrunning.Operation -} - -// CreateModelOperation returns a new CreateModelOperation from a given name. -// The name must be that of a previously created CreateModelOperation, possibly from a different process. -func (c *gRPCClient) CreateModelOperation(name string) *CreateModelOperation { - return &CreateModelOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), - } -} - -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. -// -// See documentation of Poll for error-handling information. -func (op *CreateModelOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*automlpb.Model, error) { - var resp automlpb.Model - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { +// CreateDataset creates a dataset. +func (c *restClient) CreateDataset(ctx context.Context, req *automlpb.CreateDatasetRequest, opts ...gax.CallOption) (*automlpb.Dataset, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetDataset() + jsonReq, err := m.Marshal(body) + if err != nil { return nil, err } - return &resp, nil -} -// Poll fetches the latest state of the long-running operation. -// -// Poll also fetches the latest metadata, which can be retrieved by Metadata. -// -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *CreateModelOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*automlpb.Model, error) { - var resp automlpb.Model - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - if !op.Done() { - return nil, nil - } - return &resp, nil -} + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/datasets", req.GetParent()) -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. -// If the metadata is not available, the returned metadata and error are both nil. -func (op *CreateModelOperation) Metadata() (*automlpb.OperationMetadata, error) { - var meta automlpb.OperationMetadata - if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { - return nil, nil - } else if err != nil { - return nil, err - } - return &meta, nil -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) -// Done reports whether the long-running operation has completed. -func (op *CreateModelOperation) Done() bool { - return op.lro.Done() -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateDataset[0:len((*c.CallOptions).CreateDataset):len((*c.CallOptions).CreateDataset)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &automlpb.Dataset{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// Name returns the name of the long-running operation. -// The name is assigned by the server and is unique within the service from which the operation is created. -func (op *CreateModelOperation) Name() string { - return op.lro.Name() -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// DeleteDatasetOperation manages a long-running operation from DeleteDataset. -type DeleteDatasetOperation struct { - lro *longrunning.Operation -} + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } -// DeleteDatasetOperation returns a new DeleteDatasetOperation from a given name. -// The name must be that of a previously created DeleteDatasetOperation, possibly from a different process. -func (c *gRPCClient) DeleteDatasetOperation(name string) *DeleteDatasetOperation { - return &DeleteDatasetOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e } + return resp, nil } -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. -// +// GetDataset gets a dataset. +func (c *restClient) GetDataset(ctx context.Context, req *automlpb.GetDatasetRequest, opts ...gax.CallOption) (*automlpb.Dataset, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetDataset[0:len((*c.CallOptions).GetDataset):len((*c.CallOptions).GetDataset)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &automlpb.Dataset{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListDatasets lists datasets in a project. +func (c *restClient) ListDatasets(ctx context.Context, req *automlpb.ListDatasetsRequest, opts ...gax.CallOption) *DatasetIterator { + it := &DatasetIterator{} + req = proto.Clone(req).(*automlpb.ListDatasetsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*automlpb.Dataset, string, error) { + resp := &automlpb.ListDatasetsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/datasets", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetDatasets(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// UpdateDataset updates a dataset. +func (c *restClient) UpdateDataset(ctx context.Context, req *automlpb.UpdateDatasetRequest, opts ...gax.CallOption) (*automlpb.Dataset, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetDataset() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetDataset().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "dataset.name", url.QueryEscape(req.GetDataset().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateDataset[0:len((*c.CallOptions).UpdateDataset):len((*c.CallOptions).UpdateDataset)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &automlpb.Dataset{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteDataset deletes a dataset and all of its contents. +// Returns empty response in the +// response field when it completes, +// and delete_details in the +// metadata field. +func (c *restClient) DeleteDataset(ctx context.Context, req *automlpb.DeleteDatasetRequest, opts ...gax.CallOption) (*DeleteDatasetOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &DeleteDatasetOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ImportData imports data into a dataset. +// For Tables this method can only be called on an empty Dataset. +// +// For Tables: +// +// A +// schema_inference_version +// parameter must be explicitly set. +// Returns an empty response in the +// response field when it completes. +func (c *restClient) ImportData(ctx context.Context, req *automlpb.ImportDataRequest, opts ...gax.CallOption) (*ImportDataOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:importData", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &ImportDataOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ExportData exports dataset’s data to the provided output location. +// Returns an empty response in the +// response field when it completes. +func (c *restClient) ExportData(ctx context.Context, req *automlpb.ExportDataRequest, opts ...gax.CallOption) (*ExportDataOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:exportData", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &ExportDataOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// GetAnnotationSpec gets an annotation spec. +func (c *restClient) GetAnnotationSpec(ctx context.Context, req *automlpb.GetAnnotationSpecRequest, opts ...gax.CallOption) (*automlpb.AnnotationSpec, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetAnnotationSpec[0:len((*c.CallOptions).GetAnnotationSpec):len((*c.CallOptions).GetAnnotationSpec)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &automlpb.AnnotationSpec{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetTableSpec gets a table spec. +func (c *restClient) GetTableSpec(ctx context.Context, req *automlpb.GetTableSpecRequest, opts ...gax.CallOption) (*automlpb.TableSpec, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetFieldMask().GetPaths() != nil { + params.Add("fieldMask.paths", fmt.Sprintf("%v", req.GetFieldMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetTableSpec[0:len((*c.CallOptions).GetTableSpec):len((*c.CallOptions).GetTableSpec)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &automlpb.TableSpec{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListTableSpecs lists table specs in a dataset. +func (c *restClient) ListTableSpecs(ctx context.Context, req *automlpb.ListTableSpecsRequest, opts ...gax.CallOption) *TableSpecIterator { + it := &TableSpecIterator{} + req = proto.Clone(req).(*automlpb.ListTableSpecsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*automlpb.TableSpec, string, error) { + resp := &automlpb.ListTableSpecsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/tableSpecs", req.GetParent()) + + params := url.Values{} + if req.GetFieldMask().GetPaths() != nil { + params.Add("fieldMask.paths", fmt.Sprintf("%v", req.GetFieldMask().GetPaths())) + } + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetTableSpecs(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// UpdateTableSpec updates a table spec. +func (c *restClient) UpdateTableSpec(ctx context.Context, req *automlpb.UpdateTableSpecRequest, opts ...gax.CallOption) (*automlpb.TableSpec, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetTableSpec() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetTableSpec().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "table_spec.name", url.QueryEscape(req.GetTableSpec().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateTableSpec[0:len((*c.CallOptions).UpdateTableSpec):len((*c.CallOptions).UpdateTableSpec)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &automlpb.TableSpec{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetColumnSpec gets a column spec. +func (c *restClient) GetColumnSpec(ctx context.Context, req *automlpb.GetColumnSpecRequest, opts ...gax.CallOption) (*automlpb.ColumnSpec, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetFieldMask().GetPaths() != nil { + params.Add("fieldMask.paths", fmt.Sprintf("%v", req.GetFieldMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetColumnSpec[0:len((*c.CallOptions).GetColumnSpec):len((*c.CallOptions).GetColumnSpec)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &automlpb.ColumnSpec{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListColumnSpecs lists column specs in a table spec. +func (c *restClient) ListColumnSpecs(ctx context.Context, req *automlpb.ListColumnSpecsRequest, opts ...gax.CallOption) *ColumnSpecIterator { + it := &ColumnSpecIterator{} + req = proto.Clone(req).(*automlpb.ListColumnSpecsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*automlpb.ColumnSpec, string, error) { + resp := &automlpb.ListColumnSpecsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/columnSpecs", req.GetParent()) + + params := url.Values{} + if req.GetFieldMask().GetPaths() != nil { + params.Add("fieldMask.paths", fmt.Sprintf("%v", req.GetFieldMask().GetPaths())) + } + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetColumnSpecs(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// UpdateColumnSpec updates a column spec. +func (c *restClient) UpdateColumnSpec(ctx context.Context, req *automlpb.UpdateColumnSpecRequest, opts ...gax.CallOption) (*automlpb.ColumnSpec, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetColumnSpec() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetColumnSpec().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "column_spec.name", url.QueryEscape(req.GetColumnSpec().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateColumnSpec[0:len((*c.CallOptions).UpdateColumnSpec):len((*c.CallOptions).UpdateColumnSpec)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &automlpb.ColumnSpec{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateModel creates a model. +// Returns a Model in the response +// field when it completes. +// When you create a model, several model evaluations are created for it: +// a global evaluation, and one evaluation for each annotation spec. +func (c *restClient) CreateModel(ctx context.Context, req *automlpb.CreateModelRequest, opts ...gax.CallOption) (*CreateModelOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetModel() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/models", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &CreateModelOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// GetModel gets a model. +func (c *restClient) GetModel(ctx context.Context, req *automlpb.GetModelRequest, opts ...gax.CallOption) (*automlpb.Model, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetModel[0:len((*c.CallOptions).GetModel):len((*c.CallOptions).GetModel)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &automlpb.Model{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListModels lists models. +func (c *restClient) ListModels(ctx context.Context, req *automlpb.ListModelsRequest, opts ...gax.CallOption) *ModelIterator { + it := &ModelIterator{} + req = proto.Clone(req).(*automlpb.ListModelsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*automlpb.Model, string, error) { + resp := &automlpb.ListModelsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/models", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetModel(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// DeleteModel deletes a model. +// Returns google.protobuf.Empty in the +// response field when it completes, +// and delete_details in the +// metadata field. +func (c *restClient) DeleteModel(ctx context.Context, req *automlpb.DeleteModelRequest, opts ...gax.CallOption) (*DeleteModelOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &DeleteModelOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// DeployModel deploys a model. If a model is already deployed, deploying it with the +// same parameters has no effect. Deploying with different parametrs +// (as e.g. changing +// +// node_number) +// will reset the deployment state without pausing the model’s availability. +// +// Only applicable for Text Classification, Image Object Detection , Tables, and Image Segmentation; all other domains manage +// deployment automatically. +// +// Returns an empty response in the +// response field when it completes. +func (c *restClient) DeployModel(ctx context.Context, req *automlpb.DeployModelRequest, opts ...gax.CallOption) (*DeployModelOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:deploy", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &DeployModelOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UndeployModel undeploys a model. If the model is not deployed this method has no effect. +// +// Only applicable for Text Classification, Image Object Detection and Tables; +// all other domains manage deployment automatically. +// +// Returns an empty response in the +// response field when it completes. +func (c *restClient) UndeployModel(ctx context.Context, req *automlpb.UndeployModelRequest, opts ...gax.CallOption) (*UndeployModelOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:undeploy", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &UndeployModelOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ExportModel exports a trained, “export-able”, model to a user specified Google Cloud +// Storage location. A model is considered export-able if and only if it has +// an export format defined for it in +// +// ModelExportOutputConfig. +// +// Returns an empty response in the +// response field when it completes. +func (c *restClient) ExportModel(ctx context.Context, req *automlpb.ExportModelRequest, opts ...gax.CallOption) (*ExportModelOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:export", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &ExportModelOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ExportEvaluatedExamples exports examples on which the model was evaluated (i.e. which were in the +// TEST set of the dataset the model was created from), together with their +// ground truth annotations and the annotations created (predicted) by the +// model. +// The examples, ground truth and predictions are exported in the state +// they were at the moment the model was evaluated. +// +// This export is available only for 30 days since the model evaluation is +// created. +// +// Currently only available for Tables. +// +// Returns an empty response in the +// response field when it completes. +func (c *restClient) ExportEvaluatedExamples(ctx context.Context, req *automlpb.ExportEvaluatedExamplesRequest, opts ...gax.CallOption) (*ExportEvaluatedExamplesOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:exportEvaluatedExamples", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &ExportEvaluatedExamplesOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// GetModelEvaluation gets a model evaluation. +func (c *restClient) GetModelEvaluation(ctx context.Context, req *automlpb.GetModelEvaluationRequest, opts ...gax.CallOption) (*automlpb.ModelEvaluation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetModelEvaluation[0:len((*c.CallOptions).GetModelEvaluation):len((*c.CallOptions).GetModelEvaluation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &automlpb.ModelEvaluation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListModelEvaluations lists model evaluations. +func (c *restClient) ListModelEvaluations(ctx context.Context, req *automlpb.ListModelEvaluationsRequest, opts ...gax.CallOption) *ModelEvaluationIterator { + it := &ModelEvaluationIterator{} + req = proto.Clone(req).(*automlpb.ListModelEvaluationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*automlpb.ModelEvaluation, string, error) { + resp := &automlpb.ListModelEvaluationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/modelEvaluations", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetModelEvaluation(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CreateModelOperation manages a long-running operation from CreateModel. +type CreateModelOperation struct { + lro *longrunning.Operation + pollPath string +} + +// CreateModelOperation returns a new CreateModelOperation from a given name. +// The name must be that of a previously created CreateModelOperation, possibly from a different process. +func (c *gRPCClient) CreateModelOperation(name string) *CreateModelOperation { + return &CreateModelOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// CreateModelOperation returns a new CreateModelOperation from a given name. +// The name must be that of a previously created CreateModelOperation, possibly from a different process. +func (c *restClient) CreateModelOperation(name string) *CreateModelOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &CreateModelOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateModelOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*automlpb.Model, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp automlpb.Model + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateModelOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*automlpb.Model, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp automlpb.Model + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateModelOperation) Metadata() (*automlpb.OperationMetadata, error) { + var meta automlpb.OperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateModelOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *CreateModelOperation) Name() string { + return op.lro.Name() +} + +// DeleteDatasetOperation manages a long-running operation from DeleteDataset. +type DeleteDatasetOperation struct { + lro *longrunning.Operation + pollPath string +} + +// DeleteDatasetOperation returns a new DeleteDatasetOperation from a given name. +// The name must be that of a previously created DeleteDatasetOperation, possibly from a different process. +func (c *gRPCClient) DeleteDatasetOperation(name string) *DeleteDatasetOperation { + return &DeleteDatasetOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// DeleteDatasetOperation returns a new DeleteDatasetOperation from a given name. +// The name must be that of a previously created DeleteDatasetOperation, possibly from a different process. +func (c *restClient) DeleteDatasetOperation(name string) *DeleteDatasetOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &DeleteDatasetOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// // See documentation of Poll for error-handling information. func (op *DeleteDatasetOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1436,6 +3377,7 @@ func (op *DeleteDatasetOperation) Wait(ctx context.Context, opts ...gax.CallOpti // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeleteDatasetOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1466,7 +3408,8 @@ func (op *DeleteDatasetOperation) Name() string { // DeleteModelOperation manages a long-running operation from DeleteModel. type DeleteModelOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // DeleteModelOperation returns a new DeleteModelOperation from a given name. @@ -1477,10 +3420,21 @@ func (c *gRPCClient) DeleteModelOperation(name string) *DeleteModelOperation { } } +// DeleteModelOperation returns a new DeleteModelOperation from a given name. +// The name must be that of a previously created DeleteModelOperation, possibly from a different process. +func (c *restClient) DeleteModelOperation(name string) *DeleteModelOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &DeleteModelOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *DeleteModelOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1494,6 +3448,7 @@ func (op *DeleteModelOperation) Wait(ctx context.Context, opts ...gax.CallOption // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeleteModelOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1524,7 +3479,8 @@ func (op *DeleteModelOperation) Name() string { // DeployModelOperation manages a long-running operation from DeployModel. type DeployModelOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // DeployModelOperation returns a new DeployModelOperation from a given name. @@ -1535,10 +3491,21 @@ func (c *gRPCClient) DeployModelOperation(name string) *DeployModelOperation { } } +// DeployModelOperation returns a new DeployModelOperation from a given name. +// The name must be that of a previously created DeployModelOperation, possibly from a different process. +func (c *restClient) DeployModelOperation(name string) *DeployModelOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &DeployModelOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *DeployModelOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1552,6 +3519,7 @@ func (op *DeployModelOperation) Wait(ctx context.Context, opts ...gax.CallOption // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeployModelOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1582,7 +3550,8 @@ func (op *DeployModelOperation) Name() string { // ExportDataOperation manages a long-running operation from ExportData. type ExportDataOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // ExportDataOperation returns a new ExportDataOperation from a given name. @@ -1593,10 +3562,21 @@ func (c *gRPCClient) ExportDataOperation(name string) *ExportDataOperation { } } +// ExportDataOperation returns a new ExportDataOperation from a given name. +// The name must be that of a previously created ExportDataOperation, possibly from a different process. +func (c *restClient) ExportDataOperation(name string) *ExportDataOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &ExportDataOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *ExportDataOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1610,6 +3590,7 @@ func (op *ExportDataOperation) Wait(ctx context.Context, opts ...gax.CallOption) // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *ExportDataOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1640,7 +3621,8 @@ func (op *ExportDataOperation) Name() string { // ExportEvaluatedExamplesOperation manages a long-running operation from ExportEvaluatedExamples. type ExportEvaluatedExamplesOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // ExportEvaluatedExamplesOperation returns a new ExportEvaluatedExamplesOperation from a given name. @@ -1651,10 +3633,21 @@ func (c *gRPCClient) ExportEvaluatedExamplesOperation(name string) *ExportEvalua } } +// ExportEvaluatedExamplesOperation returns a new ExportEvaluatedExamplesOperation from a given name. +// The name must be that of a previously created ExportEvaluatedExamplesOperation, possibly from a different process. +func (c *restClient) ExportEvaluatedExamplesOperation(name string) *ExportEvaluatedExamplesOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &ExportEvaluatedExamplesOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *ExportEvaluatedExamplesOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1668,6 +3661,7 @@ func (op *ExportEvaluatedExamplesOperation) Wait(ctx context.Context, opts ...ga // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *ExportEvaluatedExamplesOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1698,7 +3692,8 @@ func (op *ExportEvaluatedExamplesOperation) Name() string { // ExportModelOperation manages a long-running operation from ExportModel. type ExportModelOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // ExportModelOperation returns a new ExportModelOperation from a given name. @@ -1709,10 +3704,21 @@ func (c *gRPCClient) ExportModelOperation(name string) *ExportModelOperation { } } +// ExportModelOperation returns a new ExportModelOperation from a given name. +// The name must be that of a previously created ExportModelOperation, possibly from a different process. +func (c *restClient) ExportModelOperation(name string) *ExportModelOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &ExportModelOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *ExportModelOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1726,6 +3732,7 @@ func (op *ExportModelOperation) Wait(ctx context.Context, opts ...gax.CallOption // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *ExportModelOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1756,7 +3763,8 @@ func (op *ExportModelOperation) Name() string { // ImportDataOperation manages a long-running operation from ImportData. type ImportDataOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // ImportDataOperation returns a new ImportDataOperation from a given name. @@ -1767,10 +3775,21 @@ func (c *gRPCClient) ImportDataOperation(name string) *ImportDataOperation { } } +// ImportDataOperation returns a new ImportDataOperation from a given name. +// The name must be that of a previously created ImportDataOperation, possibly from a different process. +func (c *restClient) ImportDataOperation(name string) *ImportDataOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &ImportDataOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *ImportDataOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1784,6 +3803,7 @@ func (op *ImportDataOperation) Wait(ctx context.Context, opts ...gax.CallOption) // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *ImportDataOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1814,7 +3834,8 @@ func (op *ImportDataOperation) Name() string { // UndeployModelOperation manages a long-running operation from UndeployModel. type UndeployModelOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UndeployModelOperation returns a new UndeployModelOperation from a given name. @@ -1825,10 +3846,21 @@ func (c *gRPCClient) UndeployModelOperation(name string) *UndeployModelOperation } } +// UndeployModelOperation returns a new UndeployModelOperation from a given name. +// The name must be that of a previously created UndeployModelOperation, possibly from a different process. +func (c *restClient) UndeployModelOperation(name string) *UndeployModelOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &UndeployModelOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UndeployModelOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1842,6 +3874,7 @@ func (op *UndeployModelOperation) Wait(ctx context.Context, opts ...gax.CallOpti // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UndeployModelOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } diff --git a/automl/apiv1beta1/auto_ml_client_example_test.go b/automl/apiv1beta1/auto_ml_client_example_test.go index 0aa02bcee486..7d1227b110c3 100644 --- a/automl/apiv1beta1/auto_ml_client_example_test.go +++ b/automl/apiv1beta1/auto_ml_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := automl.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_CreateDataset() { ctx := context.Background() c, err := automl.NewClient(ctx) diff --git a/automl/apiv1beta1/doc.go b/automl/apiv1beta1/doc.go index ea6259c065c6..c999819da9ae 100644 --- a/automl/apiv1beta1/doc.go +++ b/automl/apiv1beta1/doc.go @@ -72,6 +72,8 @@ package automl // import "cloud.google.com/go/automl/apiv1beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -160,3 +162,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/automl/apiv1beta1/gapic_metadata.json b/automl/apiv1beta1/gapic_metadata.json index d7f1ce28366e..84f27cc8a5e2 100644 --- a/automl/apiv1beta1/gapic_metadata.json +++ b/automl/apiv1beta1/gapic_metadata.json @@ -131,6 +131,131 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "CreateDataset": { + "methods": [ + "CreateDataset" + ] + }, + "CreateModel": { + "methods": [ + "CreateModel" + ] + }, + "DeleteDataset": { + "methods": [ + "DeleteDataset" + ] + }, + "DeleteModel": { + "methods": [ + "DeleteModel" + ] + }, + "DeployModel": { + "methods": [ + "DeployModel" + ] + }, + "ExportData": { + "methods": [ + "ExportData" + ] + }, + "ExportEvaluatedExamples": { + "methods": [ + "ExportEvaluatedExamples" + ] + }, + "ExportModel": { + "methods": [ + "ExportModel" + ] + }, + "GetAnnotationSpec": { + "methods": [ + "GetAnnotationSpec" + ] + }, + "GetColumnSpec": { + "methods": [ + "GetColumnSpec" + ] + }, + "GetDataset": { + "methods": [ + "GetDataset" + ] + }, + "GetModel": { + "methods": [ + "GetModel" + ] + }, + "GetModelEvaluation": { + "methods": [ + "GetModelEvaluation" + ] + }, + "GetTableSpec": { + "methods": [ + "GetTableSpec" + ] + }, + "ImportData": { + "methods": [ + "ImportData" + ] + }, + "ListColumnSpecs": { + "methods": [ + "ListColumnSpecs" + ] + }, + "ListDatasets": { + "methods": [ + "ListDatasets" + ] + }, + "ListModelEvaluations": { + "methods": [ + "ListModelEvaluations" + ] + }, + "ListModels": { + "methods": [ + "ListModels" + ] + }, + "ListTableSpecs": { + "methods": [ + "ListTableSpecs" + ] + }, + "UndeployModel": { + "methods": [ + "UndeployModel" + ] + }, + "UpdateColumnSpec": { + "methods": [ + "UpdateColumnSpec" + ] + }, + "UpdateDataset": { + "methods": [ + "UpdateDataset" + ] + }, + "UpdateTableSpec": { + "methods": [ + "UpdateTableSpec" + ] + } + } } } }, @@ -150,6 +275,21 @@ ] } } + }, + "rest": { + "libraryClient": "PredictionClient", + "rpcs": { + "BatchPredict": { + "methods": [ + "BatchPredict" + ] + }, + "Predict": { + "methods": [ + "Predict" + ] + } + } } } } diff --git a/automl/apiv1beta1/prediction_client.go b/automl/apiv1beta1/prediction_client.go index c3be5c5d9acc..589970a681f4 100644 --- a/automl/apiv1beta1/prediction_client.go +++ b/automl/apiv1beta1/prediction_client.go @@ -17,22 +17,28 @@ package automl import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" automlpb "google.golang.org/genproto/googleapis/cloud/automl/v1beta1" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newPredictionClientHook clientHook @@ -62,6 +68,13 @@ func defaultPredictionCallOptions() *PredictionCallOptions { } } +func defaultPredictionRESTCallOptions() *PredictionCallOptions { + return &PredictionCallOptions{ + Predict: []gax.CallOption{}, + BatchPredict: []gax.CallOption{}, + } +} + // internalPredictionClient is an interface that defines the methods available from Cloud AutoML API. type internalPredictionClient interface { Close() error @@ -270,6 +283,92 @@ func (c *predictionGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type predictionRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing PredictionClient + CallOptions **PredictionCallOptions +} + +// NewPredictionRESTClient creates a new prediction service rest client. +// +// AutoML Prediction API. +// +// On any input that is documented to expect a string parameter in +// snake_case or kebab-case, either of those cases is accepted. +func NewPredictionRESTClient(ctx context.Context, opts ...option.ClientOption) (*PredictionClient, error) { + clientOpts := append(defaultPredictionRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultPredictionRESTCallOptions() + c := &predictionRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &PredictionClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultPredictionRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://automl.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://automl.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://automl.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *predictionRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *predictionRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *predictionRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *predictionGRPCClient) Predict(ctx context.Context, req *automlpb.PredictRequest, opts ...gax.CallOption) (*automlpb.PredictResponse, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -316,9 +415,173 @@ func (c *predictionGRPCClient) BatchPredict(ctx context.Context, req *automlpb.B }, nil } +// Predict perform an online prediction. The prediction result will be directly +// returned in the response. +// Available for following ML problems, and their expected request payloads: +// +// Image Classification - Image in .JPEG, .GIF or .PNG format, image_bytes +// up to 30MB. +// +// Image Object Detection - Image in .JPEG, .GIF or .PNG format, image_bytes +// up to 30MB. +// +// Text Classification - TextSnippet, content up to 60,000 characters, +// UTF-8 encoded. +// +// Text Extraction - TextSnippet, content up to 30,000 characters, +// UTF-8 NFC encoded. +// +// Translation - TextSnippet, content up to 25,000 characters, UTF-8 +// encoded. +// +// Tables - Row, with column values matching the columns of the model, +// up to 5MB. Not available for FORECASTING +// +// prediction_type. +// +// Text Sentiment - TextSnippet, content up 500 characters, UTF-8 +// encoded. +func (c *predictionRESTClient) Predict(ctx context.Context, req *automlpb.PredictRequest, opts ...gax.CallOption) (*automlpb.PredictResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:predict", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).Predict[0:len((*c.CallOptions).Predict):len((*c.CallOptions).Predict)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &automlpb.PredictResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// BatchPredict perform a batch prediction. Unlike the online Predict, batch +// prediction result won’t be immediately available in the response. Instead, +// a long running operation object is returned. User can poll the operation +// result via GetOperation +// method. Once the operation is done, BatchPredictResult is returned in +// the response field. +// Available for following ML problems: +// +// Image Classification +// +// Image Object Detection +// +// Video Classification +// +// Video Object Tracking * Text Extraction +// +// Tables +func (c *predictionRESTClient) BatchPredict(ctx context.Context, req *automlpb.BatchPredictRequest, opts ...gax.CallOption) (*BatchPredictOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:batchPredict", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &BatchPredictOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + // BatchPredictOperation manages a long-running operation from BatchPredict. type BatchPredictOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // BatchPredictOperation returns a new BatchPredictOperation from a given name. @@ -329,10 +592,21 @@ func (c *predictionGRPCClient) BatchPredictOperation(name string) *BatchPredictO } } +// BatchPredictOperation returns a new BatchPredictOperation from a given name. +// The name must be that of a previously created BatchPredictOperation, possibly from a different process. +func (c *predictionRESTClient) BatchPredictOperation(name string) *BatchPredictOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &BatchPredictOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *BatchPredictOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*automlpb.BatchPredictResult, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp automlpb.BatchPredictResult if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -350,6 +624,7 @@ func (op *BatchPredictOperation) Wait(ctx context.Context, opts ...gax.CallOptio // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *BatchPredictOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*automlpb.BatchPredictResult, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp automlpb.BatchPredictResult if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/automl/apiv1beta1/prediction_client_example_test.go b/automl/apiv1beta1/prediction_client_example_test.go index 2ebfb6545927..ee611333d7ac 100644 --- a/automl/apiv1beta1/prediction_client_example_test.go +++ b/automl/apiv1beta1/prediction_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewPredictionClient() { _ = c } +func ExampleNewPredictionRESTClient() { + ctx := context.Background() + c, err := automl.NewPredictionRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExamplePredictionClient_Predict() { ctx := context.Background() c, err := automl.NewPredictionClient(ctx) diff --git a/bigquery/connection/apiv1beta1/connection_client.go b/bigquery/connection/apiv1beta1/connection_client.go index 52ce0f74b304..5cd5d0e6ca47 100644 --- a/bigquery/connection/apiv1beta1/connection_client.go +++ b/bigquery/connection/apiv1beta1/connection_client.go @@ -17,21 +17,27 @@ package connection import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" connectionpb "google.golang.org/genproto/googleapis/cloud/bigquery/connection/v1beta1" iampb "google.golang.org/genproto/googleapis/iam/v1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newClientHook clientHook @@ -108,6 +114,50 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + CreateConnection: []gax.CallOption{}, + GetConnection: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + ListConnections: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + UpdateConnection: []gax.CallOption{}, + UpdateConnectionCredential: []gax.CallOption{}, + DeleteConnection: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + GetIamPolicy: []gax.CallOption{}, + SetIamPolicy: []gax.CallOption{}, + TestIamPermissions: []gax.CallOption{}, + } +} + // internalClient is an interface that defines the methods available from BigQuery Connection API. type internalClient interface { Close() error @@ -295,6 +345,74 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new connection service rest client. +// +// Manages external data source connections and credentials. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://bigqueryconnection.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://bigqueryconnection.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://bigqueryconnection.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) CreateConnection(ctx context.Context, req *connectionpb.CreateConnectionRequest, opts ...gax.CallOption) (*connectionpb.Connection, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -484,3 +602,519 @@ func (c *gRPCClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamP } return resp, nil } + +// CreateConnection creates a new connection. +func (c *restClient) CreateConnection(ctx context.Context, req *connectionpb.CreateConnectionRequest, opts ...gax.CallOption) (*connectionpb.Connection, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetConnection() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/connections", req.GetParent()) + + params := url.Values{} + if req.GetConnectionId() != "" { + params.Add("connectionId", fmt.Sprintf("%v", req.GetConnectionId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateConnection[0:len((*c.CallOptions).CreateConnection):len((*c.CallOptions).CreateConnection)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &connectionpb.Connection{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetConnection returns specified connection. +func (c *restClient) GetConnection(ctx context.Context, req *connectionpb.GetConnectionRequest, opts ...gax.CallOption) (*connectionpb.Connection, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetConnection[0:len((*c.CallOptions).GetConnection):len((*c.CallOptions).GetConnection)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &connectionpb.Connection{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListConnections returns a list of connections in the given project. +func (c *restClient) ListConnections(ctx context.Context, req *connectionpb.ListConnectionsRequest, opts ...gax.CallOption) (*connectionpb.ListConnectionsResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/connections", req.GetParent()) + + params := url.Values{} + if req.GetMaxResults().GetValue() != 0 { + params.Add("maxResults.value", fmt.Sprintf("%v", req.GetMaxResults().GetValue())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ListConnections[0:len((*c.CallOptions).ListConnections):len((*c.CallOptions).ListConnections)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &connectionpb.ListConnectionsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateConnection updates the specified connection. For security reasons, also resets +// credential if connection properties are in the update field mask. +func (c *restClient) UpdateConnection(ctx context.Context, req *connectionpb.UpdateConnectionRequest, opts ...gax.CallOption) (*connectionpb.Connection, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetConnection() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateConnection[0:len((*c.CallOptions).UpdateConnection):len((*c.CallOptions).UpdateConnection)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &connectionpb.Connection{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateConnectionCredential sets the credential for the specified connection. +func (c *restClient) UpdateConnectionCredential(ctx context.Context, req *connectionpb.UpdateConnectionCredentialRequest, opts ...gax.CallOption) error { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetCredential() + jsonReq, err := m.Marshal(body) + if err != nil { + return err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// DeleteConnection deletes connection and associated credential. +func (c *restClient) DeleteConnection(ctx context.Context, req *connectionpb.DeleteConnectionRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetIamPolicy gets the access control policy for a resource. +// Returns an empty policy if the resource exists and does not have a policy +// set. +func (c *restClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:getIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetIamPolicy[0:len((*c.CallOptions).GetIamPolicy):len((*c.CallOptions).GetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// SetIamPolicy sets the access control policy on the specified resource. Replaces any +// existing policy. +// +// Can return Public Errors: NOT_FOUND, INVALID_ARGUMENT and PERMISSION_DENIED +func (c *restClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:setIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SetIamPolicy[0:len((*c.CallOptions).SetIamPolicy):len((*c.CallOptions).SetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// TestIamPermissions returns permissions that a caller has on the specified resource. +// If the resource does not exist, this will return an empty set of +// permissions, not a NOT_FOUND error. +// +// Note: This operation is designed to be used for building permission-aware +// UIs and command-line tools, not for authorization checking. This operation +// may “fail open” without warning. +func (c *restClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:testIamPermissions", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).TestIamPermissions[0:len((*c.CallOptions).TestIamPermissions):len((*c.CallOptions).TestIamPermissions)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.TestIamPermissionsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/bigquery/connection/apiv1beta1/connection_client_example_test.go b/bigquery/connection/apiv1beta1/connection_client_example_test.go index a97cec26ed21..9fb22454ddd9 100644 --- a/bigquery/connection/apiv1beta1/connection_client_example_test.go +++ b/bigquery/connection/apiv1beta1/connection_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := connection.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_CreateConnection() { ctx := context.Background() c, err := connection.NewClient(ctx) diff --git a/bigquery/connection/apiv1beta1/doc.go b/bigquery/connection/apiv1beta1/doc.go index 99e0bff79033..bc451786a80a 100644 --- a/bigquery/connection/apiv1beta1/doc.go +++ b/bigquery/connection/apiv1beta1/doc.go @@ -71,6 +71,8 @@ package connection // import "cloud.google.com/go/bigquery/connection/apiv1beta1 import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -160,3 +162,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/bigquery/connection/apiv1beta1/gapic_metadata.json b/bigquery/connection/apiv1beta1/gapic_metadata.json index 380ae9f12c38..aed144542e4a 100644 --- a/bigquery/connection/apiv1beta1/gapic_metadata.json +++ b/bigquery/connection/apiv1beta1/gapic_metadata.json @@ -56,6 +56,56 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "CreateConnection": { + "methods": [ + "CreateConnection" + ] + }, + "DeleteConnection": { + "methods": [ + "DeleteConnection" + ] + }, + "GetConnection": { + "methods": [ + "GetConnection" + ] + }, + "GetIamPolicy": { + "methods": [ + "GetIamPolicy" + ] + }, + "ListConnections": { + "methods": [ + "ListConnections" + ] + }, + "SetIamPolicy": { + "methods": [ + "SetIamPolicy" + ] + }, + "TestIamPermissions": { + "methods": [ + "TestIamPermissions" + ] + }, + "UpdateConnection": { + "methods": [ + "UpdateConnection" + ] + }, + "UpdateConnectionCredential": { + "methods": [ + "UpdateConnectionCredential" + ] + } + } } } } diff --git a/bigquery/dataexchange/apiv1beta1/analytics_hub_client.go b/bigquery/dataexchange/apiv1beta1/analytics_hub_client.go index 49b8697c5c75..d9b171abe19f 100644 --- a/bigquery/dataexchange/apiv1beta1/analytics_hub_client.go +++ b/bigquery/dataexchange/apiv1beta1/analytics_hub_client.go @@ -17,22 +17,28 @@ package dataexchange import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" dataexchangepb "google.golang.org/genproto/googleapis/cloud/bigquery/dataexchange/v1beta1" iampb "google.golang.org/genproto/googleapis/iam/v1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -254,6 +260,176 @@ func defaultAnalyticsHubCallOptions() *AnalyticsHubCallOptions { } } +func defaultAnalyticsHubRESTCallOptions() *AnalyticsHubCallOptions { + return &AnalyticsHubCallOptions{ + ListDataExchanges: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + ListOrgDataExchanges: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + GetDataExchange: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + CreateDataExchange: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + UpdateDataExchange: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + DeleteDataExchange: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + ListListings: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + GetListing: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + CreateListing: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + UpdateListing: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + DeleteListing: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + SubscribeListing: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + GetIamPolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + SetIamPolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + TestIamPermissions: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + } +} + // internalAnalyticsHubClient is an interface that defines the methods available from Analytics Hub API. type internalAnalyticsHubClient interface { Close() error @@ -479,6 +655,78 @@ func (c *analyticsHubGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type analyticsHubRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing AnalyticsHubClient + CallOptions **AnalyticsHubCallOptions +} + +// NewAnalyticsHubRESTClient creates a new analytics hub service rest client. +// +// The AnalyticsHubService API facilitates data sharing within and across +// organizations. It allows data providers to publish Listings — a +// discoverable and searchable SKU representing a dataset. Data consumers can +// subscribe to Listings. Upon subscription, AnalyticsHub provisions a “Linked +// Datasets” surfacing the data in the consumer’s project. +func NewAnalyticsHubRESTClient(ctx context.Context, opts ...option.ClientOption) (*AnalyticsHubClient, error) { + clientOpts := append(defaultAnalyticsHubRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultAnalyticsHubRESTCallOptions() + c := &analyticsHubRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &AnalyticsHubClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultAnalyticsHubRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://analyticshub.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://analyticshub.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://analyticshub.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *analyticsHubRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *analyticsHubRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *analyticsHubRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *analyticsHubGRPCClient) ListDataExchanges(ctx context.Context, req *dataexchangepb.ListDataExchangesRequest, opts ...gax.CallOption) *DataExchangeIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -870,6 +1118,949 @@ func (c *analyticsHubGRPCClient) TestIamPermissions(ctx context.Context, req *ia return resp, nil } +// ListDataExchanges lists DataExchanges in a given project and location. +func (c *analyticsHubRESTClient) ListDataExchanges(ctx context.Context, req *dataexchangepb.ListDataExchangesRequest, opts ...gax.CallOption) *DataExchangeIterator { + it := &DataExchangeIterator{} + req = proto.Clone(req).(*dataexchangepb.ListDataExchangesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataexchangepb.DataExchange, string, error) { + resp := &dataexchangepb.ListDataExchangesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/dataExchanges", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetDataExchanges(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// ListOrgDataExchanges lists DataExchanges from projects in a given organization and location. +func (c *analyticsHubRESTClient) ListOrgDataExchanges(ctx context.Context, req *dataexchangepb.ListOrgDataExchangesRequest, opts ...gax.CallOption) *DataExchangeIterator { + it := &DataExchangeIterator{} + req = proto.Clone(req).(*dataexchangepb.ListOrgDataExchangesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataexchangepb.DataExchange, string, error) { + resp := &dataexchangepb.ListOrgDataExchangesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/dataExchanges", req.GetOrganization()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetDataExchanges(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetDataExchange gets details of a single DataExchange. +func (c *analyticsHubRESTClient) GetDataExchange(ctx context.Context, req *dataexchangepb.GetDataExchangeRequest, opts ...gax.CallOption) (*dataexchangepb.DataExchange, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetDataExchange[0:len((*c.CallOptions).GetDataExchange):len((*c.CallOptions).GetDataExchange)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataexchangepb.DataExchange{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateDataExchange creates a new DataExchange in a given project and location. +func (c *analyticsHubRESTClient) CreateDataExchange(ctx context.Context, req *dataexchangepb.CreateDataExchangeRequest, opts ...gax.CallOption) (*dataexchangepb.DataExchange, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetDataExchange() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/dataExchanges", req.GetParent()) + + params := url.Values{} + params.Add("dataExchangeId", fmt.Sprintf("%v", req.GetDataExchangeId())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateDataExchange[0:len((*c.CallOptions).CreateDataExchange):len((*c.CallOptions).CreateDataExchange)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataexchangepb.DataExchange{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateDataExchange updates the parameters of a single DataExchange. +func (c *analyticsHubRESTClient) UpdateDataExchange(ctx context.Context, req *dataexchangepb.UpdateDataExchangeRequest, opts ...gax.CallOption) (*dataexchangepb.DataExchange, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetDataExchange() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetDataExchange().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "data_exchange.name", url.QueryEscape(req.GetDataExchange().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateDataExchange[0:len((*c.CallOptions).UpdateDataExchange):len((*c.CallOptions).UpdateDataExchange)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataexchangepb.DataExchange{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteDataExchange deletes a single DataExchange. +func (c *analyticsHubRESTClient) DeleteDataExchange(ctx context.Context, req *dataexchangepb.DeleteDataExchangeRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// ListListings lists Listings in a given project and location. +func (c *analyticsHubRESTClient) ListListings(ctx context.Context, req *dataexchangepb.ListListingsRequest, opts ...gax.CallOption) *ListingIterator { + it := &ListingIterator{} + req = proto.Clone(req).(*dataexchangepb.ListListingsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataexchangepb.Listing, string, error) { + resp := &dataexchangepb.ListListingsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/listings", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetListings(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetListing gets details of a single Listing. +func (c *analyticsHubRESTClient) GetListing(ctx context.Context, req *dataexchangepb.GetListingRequest, opts ...gax.CallOption) (*dataexchangepb.Listing, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetListing[0:len((*c.CallOptions).GetListing):len((*c.CallOptions).GetListing)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataexchangepb.Listing{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateListing creates a new Listing in a given project and location. +func (c *analyticsHubRESTClient) CreateListing(ctx context.Context, req *dataexchangepb.CreateListingRequest, opts ...gax.CallOption) (*dataexchangepb.Listing, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetListing() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/listings", req.GetParent()) + + params := url.Values{} + params.Add("listingId", fmt.Sprintf("%v", req.GetListingId())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateListing[0:len((*c.CallOptions).CreateListing):len((*c.CallOptions).CreateListing)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataexchangepb.Listing{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateListing updates the parameters of a single Listing. +func (c *analyticsHubRESTClient) UpdateListing(ctx context.Context, req *dataexchangepb.UpdateListingRequest, opts ...gax.CallOption) (*dataexchangepb.Listing, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetListing() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetListing().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "listing.name", url.QueryEscape(req.GetListing().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateListing[0:len((*c.CallOptions).UpdateListing):len((*c.CallOptions).UpdateListing)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataexchangepb.Listing{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteListing deletes a single Listing, as long as there are no subscriptions +// associated with the source of this Listing. +func (c *analyticsHubRESTClient) DeleteListing(ctx context.Context, req *dataexchangepb.DeleteListingRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// SubscribeListing subscribes to a single Listing. +// +// Data Exchange currently supports one type of Listing: a BigQuery dataset. +// Upon subscription to a Listing for a BigQuery dataset, Data Exchange +// creates a linked dataset in the subscriber’s project. +func (c *analyticsHubRESTClient) SubscribeListing(ctx context.Context, req *dataexchangepb.SubscribeListingRequest, opts ...gax.CallOption) (*dataexchangepb.SubscribeListingResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:subscribe", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SubscribeListing[0:len((*c.CallOptions).SubscribeListing):len((*c.CallOptions).SubscribeListing)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataexchangepb.SubscribeListingResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetIamPolicy gets the IAM policy for a dataExchange or a listing. +func (c *analyticsHubRESTClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:getIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetIamPolicy[0:len((*c.CallOptions).GetIamPolicy):len((*c.CallOptions).GetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// SetIamPolicy sets the IAM policy for a dataExchange or a listing. +func (c *analyticsHubRESTClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:setIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SetIamPolicy[0:len((*c.CallOptions).SetIamPolicy):len((*c.CallOptions).SetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// TestIamPermissions returns the permissions that a caller has on a specified dataExchange or +// listing. +func (c *analyticsHubRESTClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:testIamPermissions", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).TestIamPermissions[0:len((*c.CallOptions).TestIamPermissions):len((*c.CallOptions).TestIamPermissions)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.TestIamPermissionsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // DataExchangeIterator manages a stream of *dataexchangepb.DataExchange. type DataExchangeIterator struct { items []*dataexchangepb.DataExchange diff --git a/bigquery/dataexchange/apiv1beta1/analytics_hub_client_example_test.go b/bigquery/dataexchange/apiv1beta1/analytics_hub_client_example_test.go index 775606ab9c76..f2e5fca8610a 100644 --- a/bigquery/dataexchange/apiv1beta1/analytics_hub_client_example_test.go +++ b/bigquery/dataexchange/apiv1beta1/analytics_hub_client_example_test.go @@ -37,6 +37,18 @@ func ExampleNewAnalyticsHubClient() { _ = c } +func ExampleNewAnalyticsHubRESTClient() { + ctx := context.Background() + c, err := dataexchange.NewAnalyticsHubRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleAnalyticsHubClient_ListDataExchanges() { ctx := context.Background() c, err := dataexchange.NewAnalyticsHubClient(ctx) diff --git a/bigquery/dataexchange/apiv1beta1/doc.go b/bigquery/dataexchange/apiv1beta1/doc.go index 24de9294ba82..6ab6ef5d6beb 100644 --- a/bigquery/dataexchange/apiv1beta1/doc.go +++ b/bigquery/dataexchange/apiv1beta1/doc.go @@ -77,6 +77,8 @@ package dataexchange // import "cloud.google.com/go/bigquery/dataexchange/apiv1b import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -166,3 +168,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/bigquery/dataexchange/apiv1beta1/gapic_metadata.json b/bigquery/dataexchange/apiv1beta1/gapic_metadata.json index dfe2a749e70f..610a55cef95d 100644 --- a/bigquery/dataexchange/apiv1beta1/gapic_metadata.json +++ b/bigquery/dataexchange/apiv1beta1/gapic_metadata.json @@ -86,6 +86,86 @@ ] } } + }, + "rest": { + "libraryClient": "AnalyticsHubClient", + "rpcs": { + "CreateDataExchange": { + "methods": [ + "CreateDataExchange" + ] + }, + "CreateListing": { + "methods": [ + "CreateListing" + ] + }, + "DeleteDataExchange": { + "methods": [ + "DeleteDataExchange" + ] + }, + "DeleteListing": { + "methods": [ + "DeleteListing" + ] + }, + "GetDataExchange": { + "methods": [ + "GetDataExchange" + ] + }, + "GetIamPolicy": { + "methods": [ + "GetIamPolicy" + ] + }, + "GetListing": { + "methods": [ + "GetListing" + ] + }, + "ListDataExchanges": { + "methods": [ + "ListDataExchanges" + ] + }, + "ListListings": { + "methods": [ + "ListListings" + ] + }, + "ListOrgDataExchanges": { + "methods": [ + "ListOrgDataExchanges" + ] + }, + "SetIamPolicy": { + "methods": [ + "SetIamPolicy" + ] + }, + "SubscribeListing": { + "methods": [ + "SubscribeListing" + ] + }, + "TestIamPermissions": { + "methods": [ + "TestIamPermissions" + ] + }, + "UpdateDataExchange": { + "methods": [ + "UpdateDataExchange" + ] + }, + "UpdateListing": { + "methods": [ + "UpdateListing" + ] + } + } } } } diff --git a/bigquery/storage/apiv1beta1/big_query_storage_client.go b/bigquery/storage/apiv1beta1/big_query_storage_client.go index 2d006bf2d040..2444f8e73be7 100644 --- a/bigquery/storage/apiv1beta1/big_query_storage_client.go +++ b/bigquery/storage/apiv1beta1/big_query_storage_client.go @@ -17,20 +17,26 @@ package storage import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" storagepb "google.golang.org/genproto/googleapis/cloud/bigquery/storage/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newBigQueryStorageClientHook clientHook @@ -120,6 +126,65 @@ func defaultBigQueryStorageCallOptions() *BigQueryStorageCallOptions { } } +func defaultBigQueryStorageRESTCallOptions() *BigQueryStorageCallOptions { + return &BigQueryStorageCallOptions{ + CreateReadSession: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + ReadRows: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + BatchCreateReadSessionStreams: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + FinalizeStream: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + SplitReadStream: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + } +} + // internalBigQueryStorageClient is an interface that defines the methods available from BigQuery Storage API. type internalBigQueryStorageClient interface { Close() error @@ -321,6 +386,76 @@ func (c *bigQueryStorageGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type bigQueryStorageRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing BigQueryStorageClient + CallOptions **BigQueryStorageCallOptions +} + +// NewBigQueryStorageRESTClient creates a new big query storage rest client. +// +// BigQuery storage API. +// +// The BigQuery storage API can be used to read data stored in BigQuery. +func NewBigQueryStorageRESTClient(ctx context.Context, opts ...option.ClientOption) (*BigQueryStorageClient, error) { + clientOpts := append(defaultBigQueryStorageRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultBigQueryStorageRESTCallOptions() + c := &bigQueryStorageRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &BigQueryStorageClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultBigQueryStorageRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://bigquerystorage.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://bigquerystorage.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://bigquerystorage.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *bigQueryStorageRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *bigQueryStorageRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *bigQueryStorageRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *bigQueryStorageGRPCClient) CreateReadSession(ctx context.Context, req *storagepb.CreateReadSessionRequest, opts ...gax.CallOption) (*storagepb.ReadSession, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) @@ -420,3 +555,368 @@ func (c *bigQueryStorageGRPCClient) SplitReadStream(ctx context.Context, req *st } return resp, nil } + +// CreateReadSession creates a new read session. A read session divides the contents of a +// BigQuery table into one or more streams, which can then be used to read +// data from the table. The read session also specifies properties of the +// data to be read, such as a list of columns or a push-down filter describing +// the rows to be returned. +// +// A particular row can be read by at most one stream. When the caller has +// reached the end of each stream in the session, then all the data in the +// table has been read. +// +// Read sessions automatically expire 24 hours after they are created and do +// not require manual clean-up by the caller. +func (c *bigQueryStorageRESTClient) CreateReadSession(ctx context.Context, req *storagepb.CreateReadSessionRequest, opts ...gax.CallOption) (*storagepb.ReadSession, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetTableReference().GetProjectId()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v", "table_reference.project_id", url.QueryEscape(req.GetTableReference().GetProjectId()), "table_reference.dataset_id", url.QueryEscape(req.GetTableReference().GetDatasetId()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateReadSession[0:len((*c.CallOptions).CreateReadSession):len((*c.CallOptions).CreateReadSession)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &storagepb.ReadSession{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ReadRows reads rows from the table in the format prescribed by the read session. +// Each response contains one or more table rows, up to a maximum of 10 MiB +// per response; read requests which attempt to read individual rows larger +// than this will fail. +// +// Each request also returns a set of stream statistics reflecting the +// estimated total number of rows in the read stream. This number is computed +// based on the total table size and the number of active streams in the read +// session, and may change as other streams continue to read data. +func (c *bigQueryStorageRESTClient) ReadRows(ctx context.Context, req *storagepb.ReadRowsRequest, opts ...gax.CallOption) (storagepb.BigQueryStorage_ReadRowsClient, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetReadPosition().GetStream().GetName()) + + params := url.Values{} + if req.GetReadPosition().GetOffset() != 0 { + params.Add("readPosition.offset", fmt.Sprintf("%v", req.GetReadPosition().GetOffset())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "read_position.stream.name", url.QueryEscape(req.GetReadPosition().GetStream().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + var streamClient *readRowsRESTClient + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + streamClient = &readRowsRESTClient{ + ctx: ctx, + md: metadata.MD(httpRsp.Header), + stream: gax.NewProtoJSONStreamReader(httpRsp.Body, (&storagepb.ReadRowsResponse{}).ProtoReflect().Type()), + } + return nil + }, opts...) + + return streamClient, e +} + +// readRowsRESTClient is the stream client used to consume the server stream created by +// the REST implementation of ReadRows. +type readRowsRESTClient struct { + ctx context.Context + md metadata.MD + stream *gax.ProtoJSONStream +} + +func (c *readRowsRESTClient) Recv() (*storagepb.ReadRowsResponse, error) { + if err := c.ctx.Err(); err != nil { + defer c.stream.Close() + return nil, err + } + msg, err := c.stream.Recv() + if err != nil { + defer c.stream.Close() + return nil, err + } + res := msg.(*storagepb.ReadRowsResponse) + return res, nil +} + +func (c *readRowsRESTClient) Header() (metadata.MD, error) { + return c.md, nil +} + +func (c *readRowsRESTClient) Trailer() metadata.MD { + return c.md +} + +func (c *readRowsRESTClient) CloseSend() error { + // This is a no-op to fulfill the interface. + return fmt.Errorf("this method is not implemented for a server-stream") +} + +func (c *readRowsRESTClient) Context() context.Context { + return c.ctx +} + +func (c *readRowsRESTClient) SendMsg(m interface{}) error { + // This is a no-op to fulfill the interface. + return fmt.Errorf("this method is not implemented for a server-stream") +} + +func (c *readRowsRESTClient) RecvMsg(m interface{}) error { + // This is a no-op to fulfill the interface. + return fmt.Errorf("this method is not implemented, use Recv") +} + +// BatchCreateReadSessionStreams creates additional streams for a ReadSession. This API can be used to +// dynamically adjust the parallelism of a batch processing task upwards by +// adding additional workers. +func (c *bigQueryStorageRESTClient) BatchCreateReadSessionStreams(ctx context.Context, req *storagepb.BatchCreateReadSessionStreamsRequest, opts ...gax.CallOption) (*storagepb.BatchCreateReadSessionStreamsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetSession().GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "session.name", url.QueryEscape(req.GetSession().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).BatchCreateReadSessionStreams[0:len((*c.CallOptions).BatchCreateReadSessionStreams):len((*c.CallOptions).BatchCreateReadSessionStreams)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &storagepb.BatchCreateReadSessionStreamsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// FinalizeStream triggers the graceful termination of a single stream in a ReadSession. This +// API can be used to dynamically adjust the parallelism of a batch processing +// task downwards without losing data. +// +// This API does not delete the stream – it remains visible in the +// ReadSession, and any data processed by the stream is not released to other +// streams. However, no additional data will be assigned to the stream once +// this call completes. Callers must continue reading data on the stream until +// the end of the stream is reached so that data which has already been +// assigned to the stream will be processed. +// +// This method will return an error if there are no other live streams +// in the Session, or if SplitReadStream() has been called on the given +// Stream. +func (c *bigQueryStorageRESTClient) FinalizeStream(ctx context.Context, req *storagepb.FinalizeStreamRequest, opts ...gax.CallOption) error { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetStream().GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "stream.name", url.QueryEscape(req.GetStream().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// SplitReadStream splits a given read stream into two Streams. These streams are referred to +// as the primary and the residual of the split. The original stream can still +// be read from in the same manner as before. Both of the returned streams can +// also be read from, and the total rows return by both child streams will be +// the same as the rows read from the original stream. +// +// Moreover, the two child streams will be allocated back to back in the +// original Stream. Concretely, it is guaranteed that for streams Original, +// Primary, and Residual, that Original[0-j] = Primary[0-j] and +// Original[j-n] = Residual[0-m] once the streams have been read to +// completion. +// +// This method is guaranteed to be idempotent. +func (c *bigQueryStorageRESTClient) SplitReadStream(ctx context.Context, req *storagepb.SplitReadStreamRequest, opts ...gax.CallOption) (*storagepb.SplitReadStreamResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetOriginalStream().GetName()) + + params := url.Values{} + if req.GetFraction() != 0 { + params.Add("fraction", fmt.Sprintf("%v", req.GetFraction())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "original_stream.name", url.QueryEscape(req.GetOriginalStream().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SplitReadStream[0:len((*c.CallOptions).SplitReadStream):len((*c.CallOptions).SplitReadStream)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &storagepb.SplitReadStreamResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/bigquery/storage/apiv1beta1/big_query_storage_client_example_test.go b/bigquery/storage/apiv1beta1/big_query_storage_client_example_test.go index 201f3ec3d902..c6a63a213b46 100644 --- a/bigquery/storage/apiv1beta1/big_query_storage_client_example_test.go +++ b/bigquery/storage/apiv1beta1/big_query_storage_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewBigQueryStorageClient() { _ = c } +func ExampleNewBigQueryStorageRESTClient() { + ctx := context.Background() + c, err := storage.NewBigQueryStorageRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleBigQueryStorageClient_CreateReadSession() { ctx := context.Background() c, err := storage.NewBigQueryStorageClient(ctx) diff --git a/bigquery/storage/apiv1beta1/doc.go b/bigquery/storage/apiv1beta1/doc.go index 7ef3da3b28ec..3611141094c0 100644 --- a/bigquery/storage/apiv1beta1/doc.go +++ b/bigquery/storage/apiv1beta1/doc.go @@ -69,6 +69,8 @@ package storage // import "cloud.google.com/go/bigquery/storage/apiv1beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -158,3 +160,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/bigquery/storage/apiv1beta1/gapic_metadata.json b/bigquery/storage/apiv1beta1/gapic_metadata.json index 95235bc516a5..ce069e626279 100644 --- a/bigquery/storage/apiv1beta1/gapic_metadata.json +++ b/bigquery/storage/apiv1beta1/gapic_metadata.json @@ -36,6 +36,36 @@ ] } } + }, + "rest": { + "libraryClient": "BigQueryStorageClient", + "rpcs": { + "BatchCreateReadSessionStreams": { + "methods": [ + "BatchCreateReadSessionStreams" + ] + }, + "CreateReadSession": { + "methods": [ + "CreateReadSession" + ] + }, + "FinalizeStream": { + "methods": [ + "FinalizeStream" + ] + }, + "ReadRows": { + "methods": [ + "ReadRows" + ] + }, + "SplitReadStream": { + "methods": [ + "SplitReadStream" + ] + } + } } } } diff --git a/bigquery/storage/apiv1beta2/big_query_read_client.go b/bigquery/storage/apiv1beta2/big_query_read_client.go index e694f102b426..623e16d58fb6 100644 --- a/bigquery/storage/apiv1beta2/big_query_read_client.go +++ b/bigquery/storage/apiv1beta2/big_query_read_client.go @@ -17,20 +17,26 @@ package storage import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" storagepb "google.golang.org/genproto/googleapis/cloud/bigquery/storage/v1beta2" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newBigQueryReadClientHook clientHook @@ -94,6 +100,43 @@ func defaultBigQueryReadCallOptions() *BigQueryReadCallOptions { } } +func defaultBigQueryReadRESTCallOptions() *BigQueryReadCallOptions { + return &BigQueryReadCallOptions{ + CreateReadSession: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + ReadRows: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + SplitReadStream: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + } +} + // internalBigQueryReadClient is an interface that defines the methods available from BigQuery Storage API. type internalBigQueryReadClient interface { Close() error @@ -278,6 +321,79 @@ func (c *bigQueryReadGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type bigQueryReadRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing BigQueryReadClient + CallOptions **BigQueryReadCallOptions +} + +// NewBigQueryReadRESTClient creates a new big query read rest client. +// +// BigQuery Read API. +// +// The Read API can be used to read data from BigQuery. +// +// New code should use the v1 Read API going forward, if they don’t use Write +// API at the same time. +func NewBigQueryReadRESTClient(ctx context.Context, opts ...option.ClientOption) (*BigQueryReadClient, error) { + clientOpts := append(defaultBigQueryReadRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultBigQueryReadRESTCallOptions() + c := &bigQueryReadRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &BigQueryReadClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultBigQueryReadRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://bigquerystorage.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://bigquerystorage.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://bigquerystorage.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *bigQueryReadRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *bigQueryReadRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *bigQueryReadRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *bigQueryReadGRPCClient) CreateReadSession(ctx context.Context, req *storagepb.CreateReadSessionRequest, opts ...gax.CallOption) (*storagepb.ReadSession, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) @@ -337,3 +453,257 @@ func (c *bigQueryReadGRPCClient) SplitReadStream(ctx context.Context, req *stora } return resp, nil } + +// CreateReadSession creates a new read session. A read session divides the contents of a +// BigQuery table into one or more streams, which can then be used to read +// data from the table. The read session also specifies properties of the +// data to be read, such as a list of columns or a push-down filter describing +// the rows to be returned. +// +// A particular row can be read by at most one stream. When the caller has +// reached the end of each stream in the session, then all the data in the +// table has been read. +// +// Data is assigned to each stream such that roughly the same number of +// rows can be read from each stream. Because the server-side unit for +// assigning data is collections of rows, the API does not guarantee that +// each stream will return the same number or rows. Additionally, the +// limits are enforced based on the number of pre-filtered rows, so some +// filters can lead to lopsided assignments. +// +// Read sessions automatically expire 6 hours after they are created and do +// not require manual clean-up by the caller. +func (c *bigQueryReadRESTClient) CreateReadSession(ctx context.Context, req *storagepb.CreateReadSessionRequest, opts ...gax.CallOption) (*storagepb.ReadSession, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v", req.GetReadSession().GetTable()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "read_session.table", url.QueryEscape(req.GetReadSession().GetTable()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateReadSession[0:len((*c.CallOptions).CreateReadSession):len((*c.CallOptions).CreateReadSession)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &storagepb.ReadSession{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ReadRows reads rows from the stream in the format prescribed by the ReadSession. +// Each response contains one or more table rows, up to a maximum of 100 MiB +// per response; read requests which attempt to read individual rows larger +// than 100 MiB will fail. +// +// Each request also returns a set of stream statistics reflecting the current +// state of the stream. +func (c *bigQueryReadRESTClient) ReadRows(ctx context.Context, req *storagepb.ReadRowsRequest, opts ...gax.CallOption) (storagepb.BigQueryRead_ReadRowsClient, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v", req.GetReadStream()) + + params := url.Values{} + if req.GetOffset() != 0 { + params.Add("offset", fmt.Sprintf("%v", req.GetOffset())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "read_stream", url.QueryEscape(req.GetReadStream()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + var streamClient *readRowsRESTClient + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + streamClient = &readRowsRESTClient{ + ctx: ctx, + md: metadata.MD(httpRsp.Header), + stream: gax.NewProtoJSONStreamReader(httpRsp.Body, (&storagepb.ReadRowsResponse{}).ProtoReflect().Type()), + } + return nil + }, opts...) + + return streamClient, e +} + +// readRowsRESTClient is the stream client used to consume the server stream created by +// the REST implementation of ReadRows. +type readRowsRESTClient struct { + ctx context.Context + md metadata.MD + stream *gax.ProtoJSONStream +} + +func (c *readRowsRESTClient) Recv() (*storagepb.ReadRowsResponse, error) { + if err := c.ctx.Err(); err != nil { + defer c.stream.Close() + return nil, err + } + msg, err := c.stream.Recv() + if err != nil { + defer c.stream.Close() + return nil, err + } + res := msg.(*storagepb.ReadRowsResponse) + return res, nil +} + +func (c *readRowsRESTClient) Header() (metadata.MD, error) { + return c.md, nil +} + +func (c *readRowsRESTClient) Trailer() metadata.MD { + return c.md +} + +func (c *readRowsRESTClient) CloseSend() error { + // This is a no-op to fulfill the interface. + return fmt.Errorf("this method is not implemented for a server-stream") +} + +func (c *readRowsRESTClient) Context() context.Context { + return c.ctx +} + +func (c *readRowsRESTClient) SendMsg(m interface{}) error { + // This is a no-op to fulfill the interface. + return fmt.Errorf("this method is not implemented for a server-stream") +} + +func (c *readRowsRESTClient) RecvMsg(m interface{}) error { + // This is a no-op to fulfill the interface. + return fmt.Errorf("this method is not implemented, use Recv") +} + +// SplitReadStream splits a given ReadStream into two ReadStream objects. These +// ReadStream objects are referred to as the primary and the residual +// streams of the split. The original ReadStream can still be read from in +// the same manner as before. Both of the returned ReadStream objects can +// also be read from, and the rows returned by both child streams will be +// the same as the rows read from the original stream. +// +// Moreover, the two child streams will be allocated back-to-back in the +// original ReadStream. Concretely, it is guaranteed that for streams +// original, primary, and residual, that original[0-j] = primary[0-j] and +// original[j-n] = residual[0-m] once the streams have been read to +// completion. +func (c *bigQueryReadRESTClient) SplitReadStream(ctx context.Context, req *storagepb.SplitReadStreamRequest, opts ...gax.CallOption) (*storagepb.SplitReadStreamResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v", req.GetName()) + + params := url.Values{} + if req.GetFraction() != 0 { + params.Add("fraction", fmt.Sprintf("%v", req.GetFraction())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SplitReadStream[0:len((*c.CallOptions).SplitReadStream):len((*c.CallOptions).SplitReadStream)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &storagepb.SplitReadStreamResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/bigquery/storage/apiv1beta2/big_query_read_client_example_test.go b/bigquery/storage/apiv1beta2/big_query_read_client_example_test.go index 160e3c9d3c16..533d7dce88a2 100644 --- a/bigquery/storage/apiv1beta2/big_query_read_client_example_test.go +++ b/bigquery/storage/apiv1beta2/big_query_read_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewBigQueryReadClient() { _ = c } +func ExampleNewBigQueryReadRESTClient() { + ctx := context.Background() + c, err := storage.NewBigQueryReadRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleBigQueryReadClient_CreateReadSession() { ctx := context.Background() c, err := storage.NewBigQueryReadClient(ctx) diff --git a/bigquery/storage/apiv1beta2/big_query_write_client.go b/bigquery/storage/apiv1beta2/big_query_write_client.go index 8dcb990b05c5..b3a131be1e61 100644 --- a/bigquery/storage/apiv1beta2/big_query_write_client.go +++ b/bigquery/storage/apiv1beta2/big_query_write_client.go @@ -17,20 +17,26 @@ package storage import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" storagepb "google.golang.org/genproto/googleapis/cloud/bigquery/storage/v1beta2" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newBigQueryWriteClientHook clientHook @@ -135,6 +141,78 @@ func defaultBigQueryWriteCallOptions() *BigQueryWriteCallOptions { } } +func defaultBigQueryWriteRESTCallOptions() *BigQueryWriteCallOptions { + return &BigQueryWriteCallOptions{ + CreateWriteStream: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable, + http.StatusTooManyRequests) + }), + }, + AppendRows: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusTooManyRequests) + }), + }, + GetWriteStream: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + FinalizeWriteStream: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + BatchCommitWriteStreams: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + FlushRows: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + } +} + // internalBigQueryWriteClient is an interface that defines the methods available from BigQuery Storage API. type internalBigQueryWriteClient interface { Close() error @@ -329,6 +407,76 @@ func (c *bigQueryWriteGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type bigQueryWriteRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing BigQueryWriteClient + CallOptions **BigQueryWriteCallOptions +} + +// NewBigQueryWriteRESTClient creates a new big query write rest client. +// +// BigQuery Write API. +// +// The Write API can be used to write data to BigQuery. +func NewBigQueryWriteRESTClient(ctx context.Context, opts ...option.ClientOption) (*BigQueryWriteClient, error) { + clientOpts := append(defaultBigQueryWriteRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultBigQueryWriteRESTCallOptions() + c := &bigQueryWriteRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &BigQueryWriteClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultBigQueryWriteRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://bigquerystorage.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://bigquerystorage.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://bigquerystorage.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *bigQueryWriteRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *bigQueryWriteRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *bigQueryWriteRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *bigQueryWriteGRPCClient) CreateWriteStream(ctx context.Context, req *storagepb.CreateWriteStreamRequest, opts ...gax.CallOption) (*storagepb.WriteStream, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) @@ -453,3 +601,338 @@ func (c *bigQueryWriteGRPCClient) FlushRows(ctx context.Context, req *storagepb. } return resp, nil } + +// CreateWriteStream creates a write stream to the given table. +// Additionally, every table has a special COMMITTED stream named ‘_default’ +// to which data can be written. This stream doesn’t need to be created using +// CreateWriteStream. It is a stream that can be used simultaneously by any +// number of clients. Data written to this stream is considered committed as +// soon as an acknowledgement is received. +func (c *bigQueryWriteRESTClient) CreateWriteStream(ctx context.Context, req *storagepb.CreateWriteStreamRequest, opts ...gax.CallOption) (*storagepb.WriteStream, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetWriteStream() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateWriteStream[0:len((*c.CallOptions).CreateWriteStream):len((*c.CallOptions).CreateWriteStream)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &storagepb.WriteStream{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// AppendRows appends data to the given stream. +// +// If offset is specified, the offset is checked against the end of +// stream. The server returns OUT_OF_RANGE in AppendRowsResponse if an +// attempt is made to append to an offset beyond the current end of the stream +// or ALREADY_EXISTS if user provids an offset that has already been +// written to. User can retry with adjusted offset within the same RPC +// stream. If offset is not specified, append happens at the end of the +// stream. +// +// The response contains the offset at which the append happened. Responses +// are received in the same order in which requests are sent. There will be +// one response for each successful request. If the offset is not set in +// response, it means append didn’t happen due to some errors. If one request +// fails, all the subsequent requests will also fail until a success request +// is made again. +// +// If the stream is of PENDING type, data will only be available for read +// operations after the stream is committed. +func (c *bigQueryWriteRESTClient) AppendRows(ctx context.Context, opts ...gax.CallOption) (storagepb.BigQueryWrite_AppendRowsClient, error) { + return nil, fmt.Errorf("AppendRows not yet supported for REST clients") +} + +// GetWriteStream gets a write stream. +func (c *bigQueryWriteRESTClient) GetWriteStream(ctx context.Context, req *storagepb.GetWriteStreamRequest, opts ...gax.CallOption) (*storagepb.WriteStream, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetWriteStream[0:len((*c.CallOptions).GetWriteStream):len((*c.CallOptions).GetWriteStream)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &storagepb.WriteStream{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// FinalizeWriteStream finalize a write stream so that no new data can be appended to the +// stream. Finalize is not supported on the ‘_default’ stream. +func (c *bigQueryWriteRESTClient) FinalizeWriteStream(ctx context.Context, req *storagepb.FinalizeWriteStreamRequest, opts ...gax.CallOption) (*storagepb.FinalizeWriteStreamResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).FinalizeWriteStream[0:len((*c.CallOptions).FinalizeWriteStream):len((*c.CallOptions).FinalizeWriteStream)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &storagepb.FinalizeWriteStreamResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// BatchCommitWriteStreams atomically commits a group of PENDING streams that belong to the same +// parent table. +// Streams must be finalized before commit and cannot be committed multiple +// times. Once a stream is committed, data in the stream becomes available +// for read operations. +func (c *bigQueryWriteRESTClient) BatchCommitWriteStreams(ctx context.Context, req *storagepb.BatchCommitWriteStreamsRequest, opts ...gax.CallOption) (*storagepb.BatchCommitWriteStreamsResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v", req.GetParent()) + + params := url.Values{} + if req.GetWriteStreams() != nil { + params.Add("writeStreams", fmt.Sprintf("%v", req.GetWriteStreams())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).BatchCommitWriteStreams[0:len((*c.CallOptions).BatchCommitWriteStreams):len((*c.CallOptions).BatchCommitWriteStreams)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &storagepb.BatchCommitWriteStreamsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// FlushRows flushes rows to a BUFFERED stream. +// If users are appending rows to BUFFERED stream, flush operation is +// required in order for the rows to become available for reading. A +// Flush operation flushes up to any previously flushed offset in a BUFFERED +// stream, to the offset specified in the request. +// Flush is not supported on the _default stream, since it is not BUFFERED. +func (c *bigQueryWriteRESTClient) FlushRows(ctx context.Context, req *storagepb.FlushRowsRequest, opts ...gax.CallOption) (*storagepb.FlushRowsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v", req.GetWriteStream()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "write_stream", url.QueryEscape(req.GetWriteStream()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).FlushRows[0:len((*c.CallOptions).FlushRows):len((*c.CallOptions).FlushRows)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &storagepb.FlushRowsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/bigquery/storage/apiv1beta2/big_query_write_client_example_test.go b/bigquery/storage/apiv1beta2/big_query_write_client_example_test.go index 87f0bad23266..73443fed5dfa 100644 --- a/bigquery/storage/apiv1beta2/big_query_write_client_example_test.go +++ b/bigquery/storage/apiv1beta2/big_query_write_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewBigQueryWriteClient() { _ = c } +func ExampleNewBigQueryWriteRESTClient() { + ctx := context.Background() + c, err := storage.NewBigQueryWriteRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleBigQueryWriteClient_CreateWriteStream() { ctx := context.Background() c, err := storage.NewBigQueryWriteClient(ctx) diff --git a/bigquery/storage/apiv1beta2/doc.go b/bigquery/storage/apiv1beta2/doc.go index cb304e6ef208..a1809f91a18c 100644 --- a/bigquery/storage/apiv1beta2/doc.go +++ b/bigquery/storage/apiv1beta2/doc.go @@ -69,6 +69,8 @@ package storage // import "cloud.google.com/go/bigquery/storage/apiv1beta2" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -159,3 +161,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/bigquery/storage/apiv1beta2/gapic_metadata.json b/bigquery/storage/apiv1beta2/gapic_metadata.json index 13e265e06a73..6064b8f07b94 100644 --- a/bigquery/storage/apiv1beta2/gapic_metadata.json +++ b/bigquery/storage/apiv1beta2/gapic_metadata.json @@ -26,6 +26,26 @@ ] } } + }, + "rest": { + "libraryClient": "BigQueryReadClient", + "rpcs": { + "CreateReadSession": { + "methods": [ + "CreateReadSession" + ] + }, + "ReadRows": { + "methods": [ + "ReadRows" + ] + }, + "SplitReadStream": { + "methods": [ + "SplitReadStream" + ] + } + } } } }, @@ -65,6 +85,41 @@ ] } } + }, + "rest": { + "libraryClient": "BigQueryWriteClient", + "rpcs": { + "AppendRows": { + "methods": [ + "AppendRows" + ] + }, + "BatchCommitWriteStreams": { + "methods": [ + "BatchCommitWriteStreams" + ] + }, + "CreateWriteStream": { + "methods": [ + "CreateWriteStream" + ] + }, + "FinalizeWriteStream": { + "methods": [ + "FinalizeWriteStream" + ] + }, + "FlushRows": { + "methods": [ + "FlushRows" + ] + }, + "GetWriteStream": { + "methods": [ + "GetWriteStream" + ] + } + } } } } diff --git a/binaryauthorization/apiv1beta1/binauthz_management_service_v1_beta1_client.go b/binaryauthorization/apiv1beta1/binauthz_management_service_v1_beta1_client.go index 5acb19d525ad..19f5d2b20a63 100644 --- a/binaryauthorization/apiv1beta1/binauthz_management_service_v1_beta1_client.go +++ b/binaryauthorization/apiv1beta1/binauthz_management_service_v1_beta1_client.go @@ -17,21 +17,27 @@ package binaryauthorization import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" binaryauthorizationpb "google.golang.org/genproto/googleapis/cloud/binaryauthorization/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -138,6 +144,78 @@ func defaultBinauthzManagementServiceV1Beta1CallOptions() *BinauthzManagementSer } } +func defaultBinauthzManagementServiceV1Beta1RESTCallOptions() *BinauthzManagementServiceV1Beta1CallOptions { + return &BinauthzManagementServiceV1Beta1CallOptions{ + GetPolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + UpdatePolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + CreateAttestor: []gax.CallOption{}, + GetAttestor: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + UpdateAttestor: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + ListAttestors: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + DeleteAttestor: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + } +} + // internalBinauthzManagementServiceV1Beta1Client is an interface that defines the methods available from Binary Authorization API. type internalBinauthzManagementServiceV1Beta1Client interface { Close() error @@ -332,6 +410,81 @@ func (c *binauthzManagementServiceV1Beta1GRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type binauthzManagementServiceV1Beta1RESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing BinauthzManagementServiceV1Beta1Client + CallOptions **BinauthzManagementServiceV1Beta1CallOptions +} + +// NewBinauthzManagementServiceV1Beta1RESTClient creates a new binauthz management service v1 beta1 rest client. +// +// Google Cloud Management Service for Binary Authorization admission policies +// and attestation authorities. +// +// This API implements a REST model with the following objects: +// +// Policy +// +// Attestor +func NewBinauthzManagementServiceV1Beta1RESTClient(ctx context.Context, opts ...option.ClientOption) (*BinauthzManagementServiceV1Beta1Client, error) { + clientOpts := append(defaultBinauthzManagementServiceV1Beta1RESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultBinauthzManagementServiceV1Beta1RESTCallOptions() + c := &binauthzManagementServiceV1Beta1RESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &BinauthzManagementServiceV1Beta1Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultBinauthzManagementServiceV1Beta1RESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://binaryauthorization.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://binaryauthorization.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://binaryauthorization.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *binauthzManagementServiceV1Beta1RESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *binauthzManagementServiceV1Beta1RESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *binauthzManagementServiceV1Beta1RESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *binauthzManagementServiceV1Beta1GRPCClient) GetPolicy(ctx context.Context, req *binaryauthorizationpb.GetPolicyRequest, opts ...gax.CallOption) (*binaryauthorizationpb.Policy, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) @@ -505,6 +658,436 @@ func (c *binauthzManagementServiceV1Beta1GRPCClient) DeleteAttestor(ctx context. return err } +// GetPolicy a policy specifies the attestors that must attest to +// a container image, before the project is allowed to deploy that +// image. There is at most one policy per project. All image admission +// requests are permitted if a project has no policy. +// +// Gets the policy for this project. Returns a default +// policy if the project does not have one. +func (c *binauthzManagementServiceV1Beta1RESTClient) GetPolicy(ctx context.Context, req *binaryauthorizationpb.GetPolicyRequest, opts ...gax.CallOption) (*binaryauthorizationpb.Policy, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetPolicy[0:len((*c.CallOptions).GetPolicy):len((*c.CallOptions).GetPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &binaryauthorizationpb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdatePolicy creates or updates a project’s policy, and returns a copy of the +// new policy. A policy is always updated as a whole, to avoid race +// conditions with concurrent policy enforcement (or management!) +// requests. Returns NOT_FOUND if the project does not exist, INVALID_ARGUMENT +// if the request is malformed. +func (c *binauthzManagementServiceV1Beta1RESTClient) UpdatePolicy(ctx context.Context, req *binaryauthorizationpb.UpdatePolicyRequest, opts ...gax.CallOption) (*binaryauthorizationpb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetPolicy() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetPolicy().GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "policy.name", url.QueryEscape(req.GetPolicy().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdatePolicy[0:len((*c.CallOptions).UpdatePolicy):len((*c.CallOptions).UpdatePolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &binaryauthorizationpb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PUT", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateAttestor creates an attestor, and returns a copy of the new +// attestor. Returns NOT_FOUND if the project does not exist, +// INVALID_ARGUMENT if the request is malformed, ALREADY_EXISTS if the +// attestor already exists. +func (c *binauthzManagementServiceV1Beta1RESTClient) CreateAttestor(ctx context.Context, req *binaryauthorizationpb.CreateAttestorRequest, opts ...gax.CallOption) (*binaryauthorizationpb.Attestor, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetAttestor() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/attestors", req.GetParent()) + + params := url.Values{} + params.Add("attestorId", fmt.Sprintf("%v", req.GetAttestorId())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateAttestor[0:len((*c.CallOptions).CreateAttestor):len((*c.CallOptions).CreateAttestor)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &binaryauthorizationpb.Attestor{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetAttestor gets an attestor. +// Returns NOT_FOUND if the attestor does not exist. +func (c *binauthzManagementServiceV1Beta1RESTClient) GetAttestor(ctx context.Context, req *binaryauthorizationpb.GetAttestorRequest, opts ...gax.CallOption) (*binaryauthorizationpb.Attestor, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetAttestor[0:len((*c.CallOptions).GetAttestor):len((*c.CallOptions).GetAttestor)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &binaryauthorizationpb.Attestor{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateAttestor updates an attestor. +// Returns NOT_FOUND if the attestor does not exist. +func (c *binauthzManagementServiceV1Beta1RESTClient) UpdateAttestor(ctx context.Context, req *binaryauthorizationpb.UpdateAttestorRequest, opts ...gax.CallOption) (*binaryauthorizationpb.Attestor, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetAttestor() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetAttestor().GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "attestor.name", url.QueryEscape(req.GetAttestor().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateAttestor[0:len((*c.CallOptions).UpdateAttestor):len((*c.CallOptions).UpdateAttestor)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &binaryauthorizationpb.Attestor{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PUT", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListAttestors lists attestors. +// Returns INVALID_ARGUMENT if the project does not exist. +func (c *binauthzManagementServiceV1Beta1RESTClient) ListAttestors(ctx context.Context, req *binaryauthorizationpb.ListAttestorsRequest, opts ...gax.CallOption) *AttestorIterator { + it := &AttestorIterator{} + req = proto.Clone(req).(*binaryauthorizationpb.ListAttestorsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*binaryauthorizationpb.Attestor, string, error) { + resp := &binaryauthorizationpb.ListAttestorsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/attestors", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetAttestors(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// DeleteAttestor deletes an attestor. Returns NOT_FOUND if the +// attestor does not exist. +func (c *binauthzManagementServiceV1Beta1RESTClient) DeleteAttestor(ctx context.Context, req *binaryauthorizationpb.DeleteAttestorRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + // AttestorIterator manages a stream of *binaryauthorizationpb.Attestor. type AttestorIterator struct { items []*binaryauthorizationpb.Attestor diff --git a/binaryauthorization/apiv1beta1/binauthz_management_service_v1_beta1_client_example_test.go b/binaryauthorization/apiv1beta1/binauthz_management_service_v1_beta1_client_example_test.go index 5e8c859c7ed1..46261ef105dd 100644 --- a/binaryauthorization/apiv1beta1/binauthz_management_service_v1_beta1_client_example_test.go +++ b/binaryauthorization/apiv1beta1/binauthz_management_service_v1_beta1_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewBinauthzManagementServiceV1Beta1Client() { _ = c } +func ExampleNewBinauthzManagementServiceV1Beta1RESTClient() { + ctx := context.Background() + c, err := binaryauthorization.NewBinauthzManagementServiceV1Beta1RESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleBinauthzManagementServiceV1Beta1Client_GetPolicy() { ctx := context.Background() c, err := binaryauthorization.NewBinauthzManagementServiceV1Beta1Client(ctx) diff --git a/binaryauthorization/apiv1beta1/doc.go b/binaryauthorization/apiv1beta1/doc.go index 98b6f768185d..e28c87dcb20c 100644 --- a/binaryauthorization/apiv1beta1/doc.go +++ b/binaryauthorization/apiv1beta1/doc.go @@ -73,6 +73,8 @@ package binaryauthorization // import "cloud.google.com/go/binaryauthorization/a import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -161,3 +163,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/binaryauthorization/apiv1beta1/gapic_metadata.json b/binaryauthorization/apiv1beta1/gapic_metadata.json index 7c86e7329aac..ba9e566c3d3b 100644 --- a/binaryauthorization/apiv1beta1/gapic_metadata.json +++ b/binaryauthorization/apiv1beta1/gapic_metadata.json @@ -46,6 +46,46 @@ ] } } + }, + "rest": { + "libraryClient": "BinauthzManagementServiceV1Beta1Client", + "rpcs": { + "CreateAttestor": { + "methods": [ + "CreateAttestor" + ] + }, + "DeleteAttestor": { + "methods": [ + "DeleteAttestor" + ] + }, + "GetAttestor": { + "methods": [ + "GetAttestor" + ] + }, + "GetPolicy": { + "methods": [ + "GetPolicy" + ] + }, + "ListAttestors": { + "methods": [ + "ListAttestors" + ] + }, + "UpdateAttestor": { + "methods": [ + "UpdateAttestor" + ] + }, + "UpdatePolicy": { + "methods": [ + "UpdatePolicy" + ] + } + } } } }, @@ -60,6 +100,16 @@ ] } } + }, + "rest": { + "libraryClient": "SystemPolicyV1Beta1Client", + "rpcs": { + "GetSystemPolicy": { + "methods": [ + "GetSystemPolicy" + ] + } + } } } } diff --git a/binaryauthorization/apiv1beta1/system_policy_v1_beta1_client.go b/binaryauthorization/apiv1beta1/system_policy_v1_beta1_client.go index 3115e7ccd78c..0bd5c2cec125 100644 --- a/binaryauthorization/apiv1beta1/system_policy_v1_beta1_client.go +++ b/binaryauthorization/apiv1beta1/system_policy_v1_beta1_client.go @@ -19,16 +19,21 @@ package binaryauthorization import ( "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" binaryauthorizationpb "google.golang.org/genproto/googleapis/cloud/binaryauthorization/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newSystemPolicyV1Beta1ClientHook clientHook @@ -56,6 +61,12 @@ func defaultSystemPolicyV1Beta1CallOptions() *SystemPolicyV1Beta1CallOptions { } } +func defaultSystemPolicyV1Beta1RESTCallOptions() *SystemPolicyV1Beta1CallOptions { + return &SystemPolicyV1Beta1CallOptions{ + GetSystemPolicy: []gax.CallOption{}, + } +} + // internalSystemPolicyV1Beta1Client is an interface that defines the methods available from Binary Authorization API. type internalSystemPolicyV1Beta1Client interface { Close() error @@ -183,6 +194,74 @@ func (c *systemPolicyV1Beta1GRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type systemPolicyV1Beta1RESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing SystemPolicyV1Beta1Client + CallOptions **SystemPolicyV1Beta1CallOptions +} + +// NewSystemPolicyV1Beta1RESTClient creates a new system policy v1 beta1 rest client. +// +// API for working with the system policy. +func NewSystemPolicyV1Beta1RESTClient(ctx context.Context, opts ...option.ClientOption) (*SystemPolicyV1Beta1Client, error) { + clientOpts := append(defaultSystemPolicyV1Beta1RESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultSystemPolicyV1Beta1RESTCallOptions() + c := &systemPolicyV1Beta1RESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &SystemPolicyV1Beta1Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultSystemPolicyV1Beta1RESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://binaryauthorization.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://binaryauthorization.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://binaryauthorization.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *systemPolicyV1Beta1RESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *systemPolicyV1Beta1RESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *systemPolicyV1Beta1RESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *systemPolicyV1Beta1GRPCClient) GetSystemPolicy(ctx context.Context, req *binaryauthorizationpb.GetSystemPolicyRequest, opts ...gax.CallOption) (*binaryauthorizationpb.Policy, error) { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) @@ -199,3 +278,56 @@ func (c *systemPolicyV1Beta1GRPCClient) GetSystemPolicy(ctx context.Context, req } return resp, nil } + +// GetSystemPolicy gets the current system policy in the specified location. +func (c *systemPolicyV1Beta1RESTClient) GetSystemPolicy(ctx context.Context, req *binaryauthorizationpb.GetSystemPolicyRequest, opts ...gax.CallOption) (*binaryauthorizationpb.Policy, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetSystemPolicy[0:len((*c.CallOptions).GetSystemPolicy):len((*c.CallOptions).GetSystemPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &binaryauthorizationpb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/binaryauthorization/apiv1beta1/system_policy_v1_beta1_client_example_test.go b/binaryauthorization/apiv1beta1/system_policy_v1_beta1_client_example_test.go index 27c971832eda..6d5b59a59dbb 100644 --- a/binaryauthorization/apiv1beta1/system_policy_v1_beta1_client_example_test.go +++ b/binaryauthorization/apiv1beta1/system_policy_v1_beta1_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewSystemPolicyV1Beta1Client() { _ = c } +func ExampleNewSystemPolicyV1Beta1RESTClient() { + ctx := context.Background() + c, err := binaryauthorization.NewSystemPolicyV1Beta1RESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleSystemPolicyV1Beta1Client_GetSystemPolicy() { ctx := context.Background() c, err := binaryauthorization.NewSystemPolicyV1Beta1Client(ctx) diff --git a/cloudtasks/apiv2beta2/cloud_tasks_client.go b/cloudtasks/apiv2beta2/cloud_tasks_client.go index 27caffe0adc2..2b032b1c7770 100644 --- a/cloudtasks/apiv2beta2/cloud_tasks_client.go +++ b/cloudtasks/apiv2beta2/cloud_tasks_client.go @@ -17,22 +17,28 @@ package cloudtasks import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2beta2" iampb "google.golang.org/genproto/googleapis/iam/v1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -187,6 +193,111 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + ListQueues: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + GetQueue: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + CreateQueue: []gax.CallOption{}, + UpdateQueue: []gax.CallOption{}, + DeleteQueue: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + PurgeQueue: []gax.CallOption{}, + PauseQueue: []gax.CallOption{}, + ResumeQueue: []gax.CallOption{}, + GetIamPolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + SetIamPolicy: []gax.CallOption{}, + TestIamPermissions: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + ListTasks: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + GetTask: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + CreateTask: []gax.CallOption{}, + DeleteTask: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + LeaseTasks: []gax.CallOption{}, + AcknowledgeTask: []gax.CallOption{}, + RenewLease: []gax.CallOption{}, + CancelLease: []gax.CallOption{}, + RunTask: []gax.CallOption{}, + } +} + // internalClient is an interface that defines the methods available from Cloud Tasks API. type internalClient interface { Close() error @@ -603,6 +714,75 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new cloud tasks rest client. +// +// Cloud Tasks allows developers to manage the execution of background +// work in their applications. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://cloudtasks.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://cloudtasks.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://cloudtasks.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) ListQueues(ctx context.Context, req *taskspb.ListQueuesRequest, opts ...gax.CallOption) *QueueIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -1077,6 +1257,1369 @@ func (c *gRPCClient) RunTask(ctx context.Context, req *taskspb.RunTaskRequest, o return resp, nil } +// ListQueues lists queues. +// +// Queues are returned in lexicographical order. +func (c *restClient) ListQueues(ctx context.Context, req *taskspb.ListQueuesRequest, opts ...gax.CallOption) *QueueIterator { + it := &QueueIterator{} + req = proto.Clone(req).(*taskspb.ListQueuesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*taskspb.Queue, string, error) { + resp := &taskspb.ListQueuesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v/queues", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetReadMask().GetPaths() != nil { + params.Add("readMask.paths", fmt.Sprintf("%v", req.GetReadMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetQueues(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetQueue gets a queue. +func (c *restClient) GetQueue(ctx context.Context, req *taskspb.GetQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v", req.GetName()) + + params := url.Values{} + if req.GetReadMask().GetPaths() != nil { + params.Add("readMask.paths", fmt.Sprintf("%v", req.GetReadMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetQueue[0:len((*c.CallOptions).GetQueue):len((*c.CallOptions).GetQueue)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Queue{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateQueue creates a queue. +// +// Queues created with this method allow tasks to live for a maximum of 31 +// days. After a task is 31 days old, the task will be deleted regardless of whether +// it was dispatched or not. +// +// WARNING: Using this method may have unintended side effects if you are +// using an App Engine queue.yaml or queue.xml file to manage your queues. +// Read +// Overview of Queue Management and +// queue.yaml (at https://cloud.google.com/tasks/docs/queue-yaml) before using +// this method. +func (c *restClient) CreateQueue(ctx context.Context, req *taskspb.CreateQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetQueue() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v/queues", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateQueue[0:len((*c.CallOptions).CreateQueue):len((*c.CallOptions).CreateQueue)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Queue{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateQueue updates a queue. +// +// This method creates the queue if it does not exist and updates +// the queue if it does exist. +// +// Queues created with this method allow tasks to live for a maximum of 31 +// days. After a task is 31 days old, the task will be deleted regardless of whether +// it was dispatched or not. +// +// WARNING: Using this method may have unintended side effects if you are +// using an App Engine queue.yaml or queue.xml file to manage your queues. +// Read +// Overview of Queue Management and +// queue.yaml (at https://cloud.google.com/tasks/docs/queue-yaml) before using +// this method. +func (c *restClient) UpdateQueue(ctx context.Context, req *taskspb.UpdateQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetQueue() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v", req.GetQueue().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "queue.name", url.QueryEscape(req.GetQueue().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateQueue[0:len((*c.CallOptions).UpdateQueue):len((*c.CallOptions).UpdateQueue)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Queue{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteQueue deletes a queue. +// +// This command will delete the queue even if it has tasks in it. +// +// Note: If you delete a queue, a queue with the same name can’t be created +// for 7 days. +// +// WARNING: Using this method may have unintended side effects if you are +// using an App Engine queue.yaml or queue.xml file to manage your queues. +// Read +// Overview of Queue Management and +// queue.yaml (at https://cloud.google.com/tasks/docs/queue-yaml) before using +// this method. +func (c *restClient) DeleteQueue(ctx context.Context, req *taskspb.DeleteQueueRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// PurgeQueue purges a queue by deleting all of its tasks. +// +// All tasks created before this method is called are permanently deleted. +// +// Purge operations can take up to one minute to take effect. Tasks +// might be dispatched before the purge takes effect. A purge is irreversible. +func (c *restClient) PurgeQueue(ctx context.Context, req *taskspb.PurgeQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v:purge", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).PurgeQueue[0:len((*c.CallOptions).PurgeQueue):len((*c.CallOptions).PurgeQueue)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Queue{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// PauseQueue pauses the queue. +// +// If a queue is paused then the system will stop dispatching tasks +// until the queue is resumed via +// ResumeQueue. Tasks can still be added +// when the queue is paused. A queue is paused if its +// state is PAUSED. +func (c *restClient) PauseQueue(ctx context.Context, req *taskspb.PauseQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v:pause", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).PauseQueue[0:len((*c.CallOptions).PauseQueue):len((*c.CallOptions).PauseQueue)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Queue{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ResumeQueue resume a queue. +// +// This method resumes a queue after it has been +// PAUSED or +// DISABLED. The state of a queue is stored +// in the queue’s state; after calling this method it +// will be set to RUNNING. +// +// WARNING: Resuming many high-QPS queues at the same time can +// lead to target overloading. If you are resuming high-QPS +// queues, follow the 500/50/5 pattern described in +// Managing Cloud Tasks Scaling +// Risks (at https://cloud.google.com/tasks/docs/manage-cloud-task-scaling). +func (c *restClient) ResumeQueue(ctx context.Context, req *taskspb.ResumeQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v:resume", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ResumeQueue[0:len((*c.CallOptions).ResumeQueue):len((*c.CallOptions).ResumeQueue)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Queue{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetIamPolicy gets the access control policy for a Queue. +// Returns an empty policy if the resource exists and does not have a policy +// set. +// +// Authorization requires the following +// Google IAM (at https://cloud.google.com/iam) permission on the specified +// resource parent: +// +// cloudtasks.queues.getIamPolicy +func (c *restClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v:getIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetIamPolicy[0:len((*c.CallOptions).GetIamPolicy):len((*c.CallOptions).GetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// SetIamPolicy sets the access control policy for a Queue. Replaces any existing +// policy. +// +// Note: The Cloud Console does not check queue-level IAM permissions yet. +// Project-level permissions are required to use the Cloud Console. +// +// Authorization requires the following +// Google IAM (at https://cloud.google.com/iam) permission on the specified +// resource parent: +// +// cloudtasks.queues.setIamPolicy +func (c *restClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v:setIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SetIamPolicy[0:len((*c.CallOptions).SetIamPolicy):len((*c.CallOptions).SetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// TestIamPermissions returns permissions that a caller has on a Queue. +// If the resource does not exist, this will return an empty set of +// permissions, not a NOT_FOUND error. +// +// Note: This operation is designed to be used for building permission-aware +// UIs and command-line tools, not for authorization checking. This operation +// may “fail open” without warning. +func (c *restClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v:testIamPermissions", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).TestIamPermissions[0:len((*c.CallOptions).TestIamPermissions):len((*c.CallOptions).TestIamPermissions)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.TestIamPermissionsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListTasks lists the tasks in a queue. +// +// By default, only the BASIC view is retrieved +// due to performance considerations; +// response_view controls the +// subset of information which is returned. +// +// The tasks may be returned in any order. The ordering may change at any +// time. +func (c *restClient) ListTasks(ctx context.Context, req *taskspb.ListTasksRequest, opts ...gax.CallOption) *TaskIterator { + it := &TaskIterator{} + req = proto.Clone(req).(*taskspb.ListTasksRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*taskspb.Task, string, error) { + resp := &taskspb.ListTasksResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v/tasks", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetResponseView() != 0 { + params.Add("responseView", fmt.Sprintf("%v", req.GetResponseView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetTasks(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetTask gets a task. +func (c *restClient) GetTask(ctx context.Context, req *taskspb.GetTaskRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v", req.GetName()) + + params := url.Values{} + if req.GetResponseView() != 0 { + params.Add("responseView", fmt.Sprintf("%v", req.GetResponseView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetTask[0:len((*c.CallOptions).GetTask):len((*c.CallOptions).GetTask)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Task{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateTask creates a task and adds it to a queue. +// +// Tasks cannot be updated after creation; there is no UpdateTask command. +// +// For [App Engine queues][google.cloud.tasks.v2beta2.AppEngineHttpTarget], the maximum task size is +// 100KB. +// +// For [pull queues][google.cloud.tasks.v2beta2.PullTarget], the maximum task size is 1MB. +func (c *restClient) CreateTask(ctx context.Context, req *taskspb.CreateTaskRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v/tasks", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateTask[0:len((*c.CallOptions).CreateTask):len((*c.CallOptions).CreateTask)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Task{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteTask deletes a task. +// +// A task can be deleted if it is scheduled or dispatched. A task +// cannot be deleted if it has completed successfully or permanently +// failed. +func (c *restClient) DeleteTask(ctx context.Context, req *taskspb.DeleteTaskRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// LeaseTasks leases tasks from a pull queue for +// lease_duration. +// +// This method is invoked by the worker to obtain a lease. The +// worker must acknowledge the task via +// AcknowledgeTask after they have +// performed the work associated with the task. +// +// The payload is intended to store data that +// the worker needs to perform the work associated with the task. To +// return the payloads in the response, set +// response_view to +// FULL. +// +// A maximum of 10 qps of LeaseTasks +// requests are allowed per +// queue. RESOURCE_EXHAUSTED +// is returned when this limit is +// exceeded. RESOURCE_EXHAUSTED +// is also returned when +// max_tasks_dispatched_per_second +// is exceeded. +func (c *restClient) LeaseTasks(ctx context.Context, req *taskspb.LeaseTasksRequest, opts ...gax.CallOption) (*taskspb.LeaseTasksResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v/tasks:lease", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).LeaseTasks[0:len((*c.CallOptions).LeaseTasks):len((*c.CallOptions).LeaseTasks)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.LeaseTasksResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// AcknowledgeTask acknowledges a pull task. +// +// The worker, that is, the entity that +// leased this task must call this method +// to indicate that the work associated with the task has finished. +// +// The worker must acknowledge a task within the +// lease_duration or the lease +// will expire and the task will become available to be leased +// again. After the task is acknowledged, it will not be returned +// by a later LeaseTasks, +// GetTask, or +// ListTasks. +func (c *restClient) AcknowledgeTask(ctx context.Context, req *taskspb.AcknowledgeTaskRequest, opts ...gax.CallOption) error { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v:acknowledge", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// RenewLease renew the current lease of a pull task. +// +// The worker can use this method to extend the lease by a new +// duration, starting from now. The new task lease will be +// returned in the task’s schedule_time. +func (c *restClient) RenewLease(ctx context.Context, req *taskspb.RenewLeaseRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v:renewLease", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).RenewLease[0:len((*c.CallOptions).RenewLease):len((*c.CallOptions).RenewLease)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Task{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CancelLease cancel a pull task’s lease. +// +// The worker can use this method to cancel a task’s lease by +// setting its schedule_time to now. This will +// make the task available to be leased to the next caller of +// LeaseTasks. +func (c *restClient) CancelLease(ctx context.Context, req *taskspb.CancelLeaseRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v:cancelLease", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CancelLease[0:len((*c.CallOptions).CancelLease):len((*c.CallOptions).CancelLease)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Task{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// RunTask forces a task to run now. +// +// When this method is called, Cloud Tasks will dispatch the task, even if +// the task is already running, the queue has reached its RateLimits or +// is PAUSED. +// +// This command is meant to be used for manual debugging. For +// example, RunTask can be used to retry a failed +// task after a fix has been made or to manually force a task to be +// dispatched now. +// +// The dispatched task is returned. That is, the task that is returned +// contains the status after the task is dispatched but +// before the task is received by its target. +// +// If Cloud Tasks receives a successful response from the task’s +// target, then the task will be deleted; otherwise the task’s +// schedule_time will be reset to the time that +// RunTask was called plus the retry delay specified +// in the queue’s RetryConfig. +// +// RunTask returns +// NOT_FOUND when it is called on a +// task that has already succeeded or permanently failed. +// +// RunTask cannot be called on a +// [pull task][google.cloud.tasks.v2beta2.PullMessage]. +func (c *restClient) RunTask(ctx context.Context, req *taskspb.RunTaskRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta2/%v:run", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).RunTask[0:len((*c.CallOptions).RunTask):len((*c.CallOptions).RunTask)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Task{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // QueueIterator manages a stream of *taskspb.Queue. type QueueIterator struct { items []*taskspb.Queue diff --git a/cloudtasks/apiv2beta2/cloud_tasks_client_example_test.go b/cloudtasks/apiv2beta2/cloud_tasks_client_example_test.go index 3b1832e25000..eaf72bfe6b5b 100644 --- a/cloudtasks/apiv2beta2/cloud_tasks_client_example_test.go +++ b/cloudtasks/apiv2beta2/cloud_tasks_client_example_test.go @@ -37,6 +37,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := cloudtasks.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_ListQueues() { ctx := context.Background() c, err := cloudtasks.NewClient(ctx) diff --git a/cloudtasks/apiv2beta2/doc.go b/cloudtasks/apiv2beta2/doc.go index 950d33d52454..9c7d920d1d88 100644 --- a/cloudtasks/apiv2beta2/doc.go +++ b/cloudtasks/apiv2beta2/doc.go @@ -77,6 +77,8 @@ package cloudtasks // import "cloud.google.com/go/cloudtasks/apiv2beta2" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -165,3 +167,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/cloudtasks/apiv2beta2/gapic_metadata.json b/cloudtasks/apiv2beta2/gapic_metadata.json index c88b99835e2d..546ae68f157c 100644 --- a/cloudtasks/apiv2beta2/gapic_metadata.json +++ b/cloudtasks/apiv2beta2/gapic_metadata.json @@ -111,6 +111,111 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "AcknowledgeTask": { + "methods": [ + "AcknowledgeTask" + ] + }, + "CancelLease": { + "methods": [ + "CancelLease" + ] + }, + "CreateQueue": { + "methods": [ + "CreateQueue" + ] + }, + "CreateTask": { + "methods": [ + "CreateTask" + ] + }, + "DeleteQueue": { + "methods": [ + "DeleteQueue" + ] + }, + "DeleteTask": { + "methods": [ + "DeleteTask" + ] + }, + "GetIamPolicy": { + "methods": [ + "GetIamPolicy" + ] + }, + "GetQueue": { + "methods": [ + "GetQueue" + ] + }, + "GetTask": { + "methods": [ + "GetTask" + ] + }, + "LeaseTasks": { + "methods": [ + "LeaseTasks" + ] + }, + "ListQueues": { + "methods": [ + "ListQueues" + ] + }, + "ListTasks": { + "methods": [ + "ListTasks" + ] + }, + "PauseQueue": { + "methods": [ + "PauseQueue" + ] + }, + "PurgeQueue": { + "methods": [ + "PurgeQueue" + ] + }, + "RenewLease": { + "methods": [ + "RenewLease" + ] + }, + "ResumeQueue": { + "methods": [ + "ResumeQueue" + ] + }, + "RunTask": { + "methods": [ + "RunTask" + ] + }, + "SetIamPolicy": { + "methods": [ + "SetIamPolicy" + ] + }, + "TestIamPermissions": { + "methods": [ + "TestIamPermissions" + ] + }, + "UpdateQueue": { + "methods": [ + "UpdateQueue" + ] + } + } } } } diff --git a/cloudtasks/apiv2beta3/cloud_tasks_client.go b/cloudtasks/apiv2beta3/cloud_tasks_client.go index eedaab5c4a64..6994c0c7543d 100644 --- a/cloudtasks/apiv2beta3/cloud_tasks_client.go +++ b/cloudtasks/apiv2beta3/cloud_tasks_client.go @@ -17,22 +17,28 @@ package cloudtasks import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2beta3" iampb "google.golang.org/genproto/googleapis/iam/v1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -179,6 +185,107 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + ListQueues: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + GetQueue: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + CreateQueue: []gax.CallOption{}, + UpdateQueue: []gax.CallOption{}, + DeleteQueue: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + PurgeQueue: []gax.CallOption{}, + PauseQueue: []gax.CallOption{}, + ResumeQueue: []gax.CallOption{}, + GetIamPolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + SetIamPolicy: []gax.CallOption{}, + TestIamPermissions: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + ListTasks: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + GetTask: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + CreateTask: []gax.CallOption{}, + DeleteTask: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + RunTask: []gax.CallOption{}, + } +} + // internalClient is an interface that defines the methods available from Cloud Tasks API. type internalClient interface { Close() error @@ -523,6 +630,75 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new cloud tasks rest client. +// +// Cloud Tasks allows developers to manage the execution of background +// work in their applications. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://cloudtasks.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://cloudtasks.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://cloudtasks.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) ListQueues(ctx context.Context, req *taskspb.ListQueuesRequest, opts ...gax.CallOption) *QueueIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -913,6 +1089,1103 @@ func (c *gRPCClient) RunTask(ctx context.Context, req *taskspb.RunTaskRequest, o return resp, nil } +// ListQueues lists queues. +// +// Queues are returned in lexicographical order. +func (c *restClient) ListQueues(ctx context.Context, req *taskspb.ListQueuesRequest, opts ...gax.CallOption) *QueueIterator { + it := &QueueIterator{} + req = proto.Clone(req).(*taskspb.ListQueuesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*taskspb.Queue, string, error) { + resp := &taskspb.ListQueuesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v/queues", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetReadMask().GetPaths() != nil { + params.Add("readMask.paths", fmt.Sprintf("%v", req.GetReadMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetQueues(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetQueue gets a queue. +func (c *restClient) GetQueue(ctx context.Context, req *taskspb.GetQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v", req.GetName()) + + params := url.Values{} + if req.GetReadMask().GetPaths() != nil { + params.Add("readMask.paths", fmt.Sprintf("%v", req.GetReadMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetQueue[0:len((*c.CallOptions).GetQueue):len((*c.CallOptions).GetQueue)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Queue{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateQueue creates a queue. +// +// Queues created with this method allow tasks to live for a maximum of 31 +// days. After a task is 31 days old, the task will be deleted regardless of whether +// it was dispatched or not. +// +// WARNING: Using this method may have unintended side effects if you are +// using an App Engine queue.yaml or queue.xml file to manage your queues. +// Read +// Overview of Queue Management and +// queue.yaml (at https://cloud.google.com/tasks/docs/queue-yaml) before using +// this method. +func (c *restClient) CreateQueue(ctx context.Context, req *taskspb.CreateQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetQueue() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v/queues", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateQueue[0:len((*c.CallOptions).CreateQueue):len((*c.CallOptions).CreateQueue)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Queue{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateQueue updates a queue. +// +// This method creates the queue if it does not exist and updates +// the queue if it does exist. +// +// Queues created with this method allow tasks to live for a maximum of 31 +// days. After a task is 31 days old, the task will be deleted regardless of whether +// it was dispatched or not. +// +// WARNING: Using this method may have unintended side effects if you are +// using an App Engine queue.yaml or queue.xml file to manage your queues. +// Read +// Overview of Queue Management and +// queue.yaml (at https://cloud.google.com/tasks/docs/queue-yaml) before using +// this method. +func (c *restClient) UpdateQueue(ctx context.Context, req *taskspb.UpdateQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetQueue() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v", req.GetQueue().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "queue.name", url.QueryEscape(req.GetQueue().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateQueue[0:len((*c.CallOptions).UpdateQueue):len((*c.CallOptions).UpdateQueue)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Queue{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteQueue deletes a queue. +// +// This command will delete the queue even if it has tasks in it. +// +// Note: If you delete a queue, a queue with the same name can’t be created +// for 7 days. +// +// WARNING: Using this method may have unintended side effects if you are +// using an App Engine queue.yaml or queue.xml file to manage your queues. +// Read +// Overview of Queue Management and +// queue.yaml (at https://cloud.google.com/tasks/docs/queue-yaml) before using +// this method. +func (c *restClient) DeleteQueue(ctx context.Context, req *taskspb.DeleteQueueRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// PurgeQueue purges a queue by deleting all of its tasks. +// +// All tasks created before this method is called are permanently deleted. +// +// Purge operations can take up to one minute to take effect. Tasks +// might be dispatched before the purge takes effect. A purge is irreversible. +func (c *restClient) PurgeQueue(ctx context.Context, req *taskspb.PurgeQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v:purge", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).PurgeQueue[0:len((*c.CallOptions).PurgeQueue):len((*c.CallOptions).PurgeQueue)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Queue{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// PauseQueue pauses the queue. +// +// If a queue is paused then the system will stop dispatching tasks +// until the queue is resumed via +// ResumeQueue. Tasks can still be added +// when the queue is paused. A queue is paused if its +// state is PAUSED. +func (c *restClient) PauseQueue(ctx context.Context, req *taskspb.PauseQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v:pause", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).PauseQueue[0:len((*c.CallOptions).PauseQueue):len((*c.CallOptions).PauseQueue)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Queue{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ResumeQueue resume a queue. +// +// This method resumes a queue after it has been +// PAUSED or +// DISABLED. The state of a queue is stored +// in the queue’s state; after calling this method it +// will be set to RUNNING. +// +// WARNING: Resuming many high-QPS queues at the same time can +// lead to target overloading. If you are resuming high-QPS +// queues, follow the 500/50/5 pattern described in +// Managing Cloud Tasks Scaling +// Risks (at https://cloud.google.com/tasks/docs/manage-cloud-task-scaling). +func (c *restClient) ResumeQueue(ctx context.Context, req *taskspb.ResumeQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v:resume", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ResumeQueue[0:len((*c.CallOptions).ResumeQueue):len((*c.CallOptions).ResumeQueue)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Queue{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetIamPolicy gets the access control policy for a Queue. +// Returns an empty policy if the resource exists and does not have a policy +// set. +// +// Authorization requires the following +// Google IAM (at https://cloud.google.com/iam) permission on the specified +// resource parent: +// +// cloudtasks.queues.getIamPolicy +func (c *restClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v:getIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetIamPolicy[0:len((*c.CallOptions).GetIamPolicy):len((*c.CallOptions).GetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// SetIamPolicy sets the access control policy for a Queue. Replaces any existing +// policy. +// +// Note: The Cloud Console does not check queue-level IAM permissions yet. +// Project-level permissions are required to use the Cloud Console. +// +// Authorization requires the following +// Google IAM (at https://cloud.google.com/iam) permission on the specified +// resource parent: +// +// cloudtasks.queues.setIamPolicy +func (c *restClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v:setIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SetIamPolicy[0:len((*c.CallOptions).SetIamPolicy):len((*c.CallOptions).SetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// TestIamPermissions returns permissions that a caller has on a Queue. +// If the resource does not exist, this will return an empty set of +// permissions, not a NOT_FOUND error. +// +// Note: This operation is designed to be used for building permission-aware +// UIs and command-line tools, not for authorization checking. This operation +// may “fail open” without warning. +func (c *restClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v:testIamPermissions", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).TestIamPermissions[0:len((*c.CallOptions).TestIamPermissions):len((*c.CallOptions).TestIamPermissions)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.TestIamPermissionsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListTasks lists the tasks in a queue. +// +// By default, only the BASIC view is retrieved +// due to performance considerations; +// response_view controls the +// subset of information which is returned. +// +// The tasks may be returned in any order. The ordering may change at any +// time. +func (c *restClient) ListTasks(ctx context.Context, req *taskspb.ListTasksRequest, opts ...gax.CallOption) *TaskIterator { + it := &TaskIterator{} + req = proto.Clone(req).(*taskspb.ListTasksRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*taskspb.Task, string, error) { + resp := &taskspb.ListTasksResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v/tasks", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetResponseView() != 0 { + params.Add("responseView", fmt.Sprintf("%v", req.GetResponseView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetTasks(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetTask gets a task. +func (c *restClient) GetTask(ctx context.Context, req *taskspb.GetTaskRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v", req.GetName()) + + params := url.Values{} + if req.GetResponseView() != 0 { + params.Add("responseView", fmt.Sprintf("%v", req.GetResponseView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetTask[0:len((*c.CallOptions).GetTask):len((*c.CallOptions).GetTask)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Task{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateTask creates a task and adds it to a queue. +// +// Tasks cannot be updated after creation; there is no UpdateTask command. +// +// The maximum task size is 100KB. +func (c *restClient) CreateTask(ctx context.Context, req *taskspb.CreateTaskRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v/tasks", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateTask[0:len((*c.CallOptions).CreateTask):len((*c.CallOptions).CreateTask)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Task{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteTask deletes a task. +// +// A task can be deleted if it is scheduled or dispatched. A task +// cannot be deleted if it has executed successfully or permanently +// failed. +func (c *restClient) DeleteTask(ctx context.Context, req *taskspb.DeleteTaskRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// RunTask forces a task to run now. +// +// When this method is called, Cloud Tasks will dispatch the task, even if +// the task is already running, the queue has reached its RateLimits or +// is PAUSED. +// +// This command is meant to be used for manual debugging. For +// example, RunTask can be used to retry a failed +// task after a fix has been made or to manually force a task to be +// dispatched now. +// +// The dispatched task is returned. That is, the task that is returned +// contains the status after the task is dispatched but +// before the task is received by its target. +// +// If Cloud Tasks receives a successful response from the task’s +// target, then the task will be deleted; otherwise the task’s +// schedule_time will be reset to the time that +// RunTask was called plus the retry delay specified +// in the queue’s RetryConfig. +// +// RunTask returns +// NOT_FOUND when it is called on a +// task that has already succeeded or permanently failed. +func (c *restClient) RunTask(ctx context.Context, req *taskspb.RunTaskRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta3/%v:run", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).RunTask[0:len((*c.CallOptions).RunTask):len((*c.CallOptions).RunTask)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &taskspb.Task{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // QueueIterator manages a stream of *taskspb.Queue. type QueueIterator struct { items []*taskspb.Queue diff --git a/cloudtasks/apiv2beta3/cloud_tasks_client_example_test.go b/cloudtasks/apiv2beta3/cloud_tasks_client_example_test.go index e312b2ff62e0..7c5708adee55 100644 --- a/cloudtasks/apiv2beta3/cloud_tasks_client_example_test.go +++ b/cloudtasks/apiv2beta3/cloud_tasks_client_example_test.go @@ -37,6 +37,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := cloudtasks.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_ListQueues() { ctx := context.Background() c, err := cloudtasks.NewClient(ctx) diff --git a/cloudtasks/apiv2beta3/doc.go b/cloudtasks/apiv2beta3/doc.go index 888c669fe49a..67a93a5de3ee 100644 --- a/cloudtasks/apiv2beta3/doc.go +++ b/cloudtasks/apiv2beta3/doc.go @@ -77,6 +77,8 @@ package cloudtasks // import "cloud.google.com/go/cloudtasks/apiv2beta3" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -165,3 +167,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/cloudtasks/apiv2beta3/gapic_metadata.json b/cloudtasks/apiv2beta3/gapic_metadata.json index 1a5f03a6d03e..a62dde808a6d 100644 --- a/cloudtasks/apiv2beta3/gapic_metadata.json +++ b/cloudtasks/apiv2beta3/gapic_metadata.json @@ -91,6 +91,91 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "CreateQueue": { + "methods": [ + "CreateQueue" + ] + }, + "CreateTask": { + "methods": [ + "CreateTask" + ] + }, + "DeleteQueue": { + "methods": [ + "DeleteQueue" + ] + }, + "DeleteTask": { + "methods": [ + "DeleteTask" + ] + }, + "GetIamPolicy": { + "methods": [ + "GetIamPolicy" + ] + }, + "GetQueue": { + "methods": [ + "GetQueue" + ] + }, + "GetTask": { + "methods": [ + "GetTask" + ] + }, + "ListQueues": { + "methods": [ + "ListQueues" + ] + }, + "ListTasks": { + "methods": [ + "ListTasks" + ] + }, + "PauseQueue": { + "methods": [ + "PauseQueue" + ] + }, + "PurgeQueue": { + "methods": [ + "PurgeQueue" + ] + }, + "ResumeQueue": { + "methods": [ + "ResumeQueue" + ] + }, + "RunTask": { + "methods": [ + "RunTask" + ] + }, + "SetIamPolicy": { + "methods": [ + "SetIamPolicy" + ] + }, + "TestIamPermissions": { + "methods": [ + "TestIamPermissions" + ] + }, + "UpdateQueue": { + "methods": [ + "UpdateQueue" + ] + } + } } } } diff --git a/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client.go b/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client.go index 6c3f4028c0f4..7b380c6cb800 100644 --- a/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client.go +++ b/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client.go @@ -17,22 +17,28 @@ package containeranalysis import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" containeranalysispb "google.golang.org/genproto/googleapis/devtools/containeranalysis/v1beta1" iampb "google.golang.org/genproto/googleapis/iam/v1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -93,6 +99,37 @@ func defaultContainerAnalysisV1Beta1CallOptions() *ContainerAnalysisV1Beta1CallO } } +func defaultContainerAnalysisV1Beta1RESTCallOptions() *ContainerAnalysisV1Beta1CallOptions { + return &ContainerAnalysisV1Beta1CallOptions{ + SetIamPolicy: []gax.CallOption{}, + GetIamPolicy: []gax.CallOption{}, + TestIamPermissions: []gax.CallOption{}, + GetScanConfig: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + ListScanConfigs: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + UpdateScanConfig: []gax.CallOption{}, + } +} + // internalContainerAnalysisV1Beta1Client is an interface that defines the methods available from Container Analysis API. type internalContainerAnalysisV1Beta1Client interface { Close() error @@ -294,6 +331,86 @@ func (c *containerAnalysisV1Beta1GRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type containerAnalysisV1Beta1RESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing ContainerAnalysisV1Beta1Client + CallOptions **ContainerAnalysisV1Beta1CallOptions +} + +// NewContainerAnalysisV1Beta1RESTClient creates a new container analysis v1 beta1 rest client. +// +// Retrieves analysis results of Cloud components such as Docker container +// images. The Container Analysis API is an implementation of the +// Grafeas (at grafeas.io) API. +// +// Analysis results are stored as a series of occurrences. An Occurrence +// contains information about a specific analysis instance on a resource. An +// occurrence refers to a Note. A note contains details describing the +// analysis and is generally stored in a separate project, called a Provider. +// Multiple occurrences can refer to the same note. +// +// For example, an SSL vulnerability could affect multiple images. In this case, +// there would be one note for the vulnerability and an occurrence for each +// image with the vulnerability referring to that note. +func NewContainerAnalysisV1Beta1RESTClient(ctx context.Context, opts ...option.ClientOption) (*ContainerAnalysisV1Beta1Client, error) { + clientOpts := append(defaultContainerAnalysisV1Beta1RESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultContainerAnalysisV1Beta1RESTCallOptions() + c := &containerAnalysisV1Beta1RESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &ContainerAnalysisV1Beta1Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultContainerAnalysisV1Beta1RESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://containeranalysis.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://containeranalysis.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://containeranalysis.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *containerAnalysisV1Beta1RESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *containerAnalysisV1Beta1RESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *containerAnalysisV1Beta1RESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *containerAnalysisV1Beta1GRPCClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond) @@ -449,6 +566,404 @@ func (c *containerAnalysisV1Beta1GRPCClient) UpdateScanConfig(ctx context.Contex return resp, nil } +// SetIamPolicy sets the access control policy on the specified note or occurrence. +// Requires containeranalysis.notes.setIamPolicy or +// containeranalysis.occurrences.setIamPolicy permission if the resource is +// a note or an occurrence, respectively. +// +// The resource takes the format projects/[PROJECT_ID]/notes/[NOTE_ID] for +// notes and projects/[PROJECT_ID]/occurrences/[OCCURRENCE_ID] for +// occurrences. +func (c *containerAnalysisV1Beta1RESTClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:setIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SetIamPolicy[0:len((*c.CallOptions).SetIamPolicy):len((*c.CallOptions).SetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetIamPolicy gets the access control policy for a note or an occurrence resource. +// Requires containeranalysis.notes.setIamPolicy or +// containeranalysis.occurrences.setIamPolicy permission if the resource is +// a note or occurrence, respectively. +// +// The resource takes the format projects/[PROJECT_ID]/notes/[NOTE_ID] for +// notes and projects/[PROJECT_ID]/occurrences/[OCCURRENCE_ID] for +// occurrences. +func (c *containerAnalysisV1Beta1RESTClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:getIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetIamPolicy[0:len((*c.CallOptions).GetIamPolicy):len((*c.CallOptions).GetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// TestIamPermissions returns the permissions that a caller has on the specified note or +// occurrence. Requires list permission on the project (for example, +// containeranalysis.notes.list). +// +// The resource takes the format projects/[PROJECT_ID]/notes/[NOTE_ID] for +// notes and projects/[PROJECT_ID]/occurrences/[OCCURRENCE_ID] for +// occurrences. +func (c *containerAnalysisV1Beta1RESTClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:testIamPermissions", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).TestIamPermissions[0:len((*c.CallOptions).TestIamPermissions):len((*c.CallOptions).TestIamPermissions)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.TestIamPermissionsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetScanConfig gets the specified scan configuration. +func (c *containerAnalysisV1Beta1RESTClient) GetScanConfig(ctx context.Context, req *containeranalysispb.GetScanConfigRequest, opts ...gax.CallOption) (*containeranalysispb.ScanConfig, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetScanConfig[0:len((*c.CallOptions).GetScanConfig):len((*c.CallOptions).GetScanConfig)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &containeranalysispb.ScanConfig{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListScanConfigs lists scan configurations for the specified project. +func (c *containerAnalysisV1Beta1RESTClient) ListScanConfigs(ctx context.Context, req *containeranalysispb.ListScanConfigsRequest, opts ...gax.CallOption) *ScanConfigIterator { + it := &ScanConfigIterator{} + req = proto.Clone(req).(*containeranalysispb.ListScanConfigsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*containeranalysispb.ScanConfig, string, error) { + resp := &containeranalysispb.ListScanConfigsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/scanConfigs", req.GetParent()) + + params := url.Values{} + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetScanConfigs(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// UpdateScanConfig updates the specified scan configuration. +func (c *containerAnalysisV1Beta1RESTClient) UpdateScanConfig(ctx context.Context, req *containeranalysispb.UpdateScanConfigRequest, opts ...gax.CallOption) (*containeranalysispb.ScanConfig, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetScanConfig() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateScanConfig[0:len((*c.CallOptions).UpdateScanConfig):len((*c.CallOptions).UpdateScanConfig)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &containeranalysispb.ScanConfig{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PUT", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // ScanConfigIterator manages a stream of *containeranalysispb.ScanConfig. type ScanConfigIterator struct { items []*containeranalysispb.ScanConfig diff --git a/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client_example_test.go b/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client_example_test.go index d227573a91dc..f447c5a61219 100644 --- a/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client_example_test.go +++ b/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client_example_test.go @@ -37,6 +37,18 @@ func ExampleNewContainerAnalysisV1Beta1Client() { _ = c } +func ExampleNewContainerAnalysisV1Beta1RESTClient() { + ctx := context.Background() + c, err := containeranalysis.NewContainerAnalysisV1Beta1RESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleContainerAnalysisV1Beta1Client_SetIamPolicy() { ctx := context.Background() c, err := containeranalysis.NewContainerAnalysisV1Beta1Client(ctx) diff --git a/containeranalysis/apiv1beta1/doc.go b/containeranalysis/apiv1beta1/doc.go index 426bf26d6ac8..be02efa7540b 100644 --- a/containeranalysis/apiv1beta1/doc.go +++ b/containeranalysis/apiv1beta1/doc.go @@ -72,6 +72,8 @@ package containeranalysis // import "cloud.google.com/go/containeranalysis/apiv1 import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -160,3 +162,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/containeranalysis/apiv1beta1/gapic_metadata.json b/containeranalysis/apiv1beta1/gapic_metadata.json index a6ea786a1c56..d9535b5a3993 100644 --- a/containeranalysis/apiv1beta1/gapic_metadata.json +++ b/containeranalysis/apiv1beta1/gapic_metadata.json @@ -86,6 +86,86 @@ ] } } + }, + "rest": { + "libraryClient": "GrafeasV1Beta1Client", + "rpcs": { + "BatchCreateNotes": { + "methods": [ + "BatchCreateNotes" + ] + }, + "BatchCreateOccurrences": { + "methods": [ + "BatchCreateOccurrences" + ] + }, + "CreateNote": { + "methods": [ + "CreateNote" + ] + }, + "CreateOccurrence": { + "methods": [ + "CreateOccurrence" + ] + }, + "DeleteNote": { + "methods": [ + "DeleteNote" + ] + }, + "DeleteOccurrence": { + "methods": [ + "DeleteOccurrence" + ] + }, + "GetNote": { + "methods": [ + "GetNote" + ] + }, + "GetOccurrence": { + "methods": [ + "GetOccurrence" + ] + }, + "GetOccurrenceNote": { + "methods": [ + "GetOccurrenceNote" + ] + }, + "GetVulnerabilityOccurrencesSummary": { + "methods": [ + "GetVulnerabilityOccurrencesSummary" + ] + }, + "ListNoteOccurrences": { + "methods": [ + "ListNoteOccurrences" + ] + }, + "ListNotes": { + "methods": [ + "ListNotes" + ] + }, + "ListOccurrences": { + "methods": [ + "ListOccurrences" + ] + }, + "UpdateNote": { + "methods": [ + "UpdateNote" + ] + }, + "UpdateOccurrence": { + "methods": [ + "UpdateOccurrence" + ] + } + } } } } diff --git a/containeranalysis/apiv1beta1/grafeas_v1_beta1_client.go b/containeranalysis/apiv1beta1/grafeas_v1_beta1_client.go index afafbe850582..36ebccfe06b0 100644 --- a/containeranalysis/apiv1beta1/grafeas_v1_beta1_client.go +++ b/containeranalysis/apiv1beta1/grafeas_v1_beta1_client.go @@ -17,21 +17,27 @@ package containeranalysis import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" grafeaspb "google.golang.org/genproto/googleapis/devtools/containeranalysis/v1beta1/grafeas" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -187,6 +193,116 @@ func defaultGrafeasV1Beta1CallOptions() *GrafeasV1Beta1CallOptions { } } +func defaultGrafeasV1Beta1RESTCallOptions() *GrafeasV1Beta1CallOptions { + return &GrafeasV1Beta1CallOptions{ + GetOccurrence: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + ListOccurrences: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + DeleteOccurrence: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + CreateOccurrence: []gax.CallOption{}, + BatchCreateOccurrences: []gax.CallOption{}, + UpdateOccurrence: []gax.CallOption{}, + GetOccurrenceNote: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + GetNote: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + ListNotes: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + DeleteNote: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + CreateNote: []gax.CallOption{}, + BatchCreateNotes: []gax.CallOption{}, + UpdateNote: []gax.CallOption{}, + ListNoteOccurrences: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + GetVulnerabilityOccurrencesSummary: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + } +} + // internalGrafeasV1Beta1Client is an interface that defines the methods available from Container Analysis API. type internalGrafeasV1Beta1Client interface { Close() error @@ -429,6 +545,87 @@ func (c *grafeasV1Beta1GRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type grafeasV1Beta1RESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing GrafeasV1Beta1Client + CallOptions **GrafeasV1Beta1CallOptions +} + +// NewGrafeasV1Beta1RESTClient creates a new grafeas v1 beta1 rest client. +// +// Grafeas (at grafeas.io) API. +// +// Retrieves analysis results of Cloud components such as Docker container +// images. +// +// Analysis results are stored as a series of occurrences. An Occurrence +// contains information about a specific analysis instance on a resource. An +// occurrence refers to a Note. A note contains details describing the +// analysis and is generally stored in a separate project, called a Provider. +// Multiple occurrences can refer to the same note. +// +// For example, an SSL vulnerability could affect multiple images. In this case, +// there would be one note for the vulnerability and an occurrence for each +// image with the vulnerability referring to that note. +func NewGrafeasV1Beta1RESTClient(ctx context.Context, opts ...option.ClientOption) (*GrafeasV1Beta1Client, error) { + clientOpts := append(defaultGrafeasV1Beta1RESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultGrafeasV1Beta1RESTCallOptions() + c := &grafeasV1Beta1RESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &GrafeasV1Beta1Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultGrafeasV1Beta1RESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://containeranalysis.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://containeranalysis.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://containeranalysis.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *grafeasV1Beta1RESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *grafeasV1Beta1RESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *grafeasV1Beta1RESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *grafeasV1Beta1GRPCClient) GetOccurrence(ctx context.Context, req *grafeaspb.GetOccurrenceRequest, opts ...gax.CallOption) (*grafeaspb.Occurrence, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond) @@ -820,6 +1017,949 @@ func (c *grafeasV1Beta1GRPCClient) GetVulnerabilityOccurrencesSummary(ctx contex return resp, nil } +// GetOccurrence gets the specified occurrence. +func (c *grafeasV1Beta1RESTClient) GetOccurrence(ctx context.Context, req *grafeaspb.GetOccurrenceRequest, opts ...gax.CallOption) (*grafeaspb.Occurrence, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOccurrence[0:len((*c.CallOptions).GetOccurrence):len((*c.CallOptions).GetOccurrence)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &grafeaspb.Occurrence{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOccurrences lists occurrences for the specified project. +func (c *grafeasV1Beta1RESTClient) ListOccurrences(ctx context.Context, req *grafeaspb.ListOccurrencesRequest, opts ...gax.CallOption) *OccurrenceIterator { + it := &OccurrenceIterator{} + req = proto.Clone(req).(*grafeaspb.ListOccurrencesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*grafeaspb.Occurrence, string, error) { + resp := &grafeaspb.ListOccurrencesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/occurrences", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOccurrences(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// DeleteOccurrence deletes the specified occurrence. For example, use this method to delete an +// occurrence when the occurrence is no longer applicable for the given +// resource. +func (c *grafeasV1Beta1RESTClient) DeleteOccurrence(ctx context.Context, req *grafeaspb.DeleteOccurrenceRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// CreateOccurrence creates a new occurrence. +func (c *grafeasV1Beta1RESTClient) CreateOccurrence(ctx context.Context, req *grafeaspb.CreateOccurrenceRequest, opts ...gax.CallOption) (*grafeaspb.Occurrence, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetOccurrence() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/occurrences", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateOccurrence[0:len((*c.CallOptions).CreateOccurrence):len((*c.CallOptions).CreateOccurrence)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &grafeaspb.Occurrence{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// BatchCreateOccurrences creates new occurrences in batch. +func (c *grafeasV1Beta1RESTClient) BatchCreateOccurrences(ctx context.Context, req *grafeaspb.BatchCreateOccurrencesRequest, opts ...gax.CallOption) (*grafeaspb.BatchCreateOccurrencesResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/occurrences:batchCreate", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).BatchCreateOccurrences[0:len((*c.CallOptions).BatchCreateOccurrences):len((*c.CallOptions).BatchCreateOccurrences)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &grafeaspb.BatchCreateOccurrencesResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateOccurrence updates the specified occurrence. +func (c *grafeasV1Beta1RESTClient) UpdateOccurrence(ctx context.Context, req *grafeaspb.UpdateOccurrenceRequest, opts ...gax.CallOption) (*grafeaspb.Occurrence, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetOccurrence() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateOccurrence[0:len((*c.CallOptions).UpdateOccurrence):len((*c.CallOptions).UpdateOccurrence)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &grafeaspb.Occurrence{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetOccurrenceNote gets the note attached to the specified occurrence. Consumer projects can +// use this method to get a note that belongs to a provider project. +func (c *grafeasV1Beta1RESTClient) GetOccurrenceNote(ctx context.Context, req *grafeaspb.GetOccurrenceNoteRequest, opts ...gax.CallOption) (*grafeaspb.Note, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/notes", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOccurrenceNote[0:len((*c.CallOptions).GetOccurrenceNote):len((*c.CallOptions).GetOccurrenceNote)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &grafeaspb.Note{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetNote gets the specified note. +func (c *grafeasV1Beta1RESTClient) GetNote(ctx context.Context, req *grafeaspb.GetNoteRequest, opts ...gax.CallOption) (*grafeaspb.Note, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetNote[0:len((*c.CallOptions).GetNote):len((*c.CallOptions).GetNote)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &grafeaspb.Note{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListNotes lists notes for the specified project. +func (c *grafeasV1Beta1RESTClient) ListNotes(ctx context.Context, req *grafeaspb.ListNotesRequest, opts ...gax.CallOption) *NoteIterator { + it := &NoteIterator{} + req = proto.Clone(req).(*grafeaspb.ListNotesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*grafeaspb.Note, string, error) { + resp := &grafeaspb.ListNotesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/notes", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetNotes(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// DeleteNote deletes the specified note. +func (c *grafeasV1Beta1RESTClient) DeleteNote(ctx context.Context, req *grafeaspb.DeleteNoteRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// CreateNote creates a new note. +func (c *grafeasV1Beta1RESTClient) CreateNote(ctx context.Context, req *grafeaspb.CreateNoteRequest, opts ...gax.CallOption) (*grafeaspb.Note, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetNote() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/notes", req.GetParent()) + + params := url.Values{} + if req.GetNoteId() != "" { + params.Add("noteId", fmt.Sprintf("%v", req.GetNoteId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateNote[0:len((*c.CallOptions).CreateNote):len((*c.CallOptions).CreateNote)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &grafeaspb.Note{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// BatchCreateNotes creates new notes in batch. +func (c *grafeasV1Beta1RESTClient) BatchCreateNotes(ctx context.Context, req *grafeaspb.BatchCreateNotesRequest, opts ...gax.CallOption) (*grafeaspb.BatchCreateNotesResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/notes:batchCreate", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).BatchCreateNotes[0:len((*c.CallOptions).BatchCreateNotes):len((*c.CallOptions).BatchCreateNotes)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &grafeaspb.BatchCreateNotesResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateNote updates the specified note. +func (c *grafeasV1Beta1RESTClient) UpdateNote(ctx context.Context, req *grafeaspb.UpdateNoteRequest, opts ...gax.CallOption) (*grafeaspb.Note, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetNote() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateNote[0:len((*c.CallOptions).UpdateNote):len((*c.CallOptions).UpdateNote)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &grafeaspb.Note{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListNoteOccurrences lists occurrences referencing the specified note. Provider projects can use +// this method to get all occurrences across consumer projects referencing the +// specified note. +func (c *grafeasV1Beta1RESTClient) ListNoteOccurrences(ctx context.Context, req *grafeaspb.ListNoteOccurrencesRequest, opts ...gax.CallOption) *OccurrenceIterator { + it := &OccurrenceIterator{} + req = proto.Clone(req).(*grafeaspb.ListNoteOccurrencesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*grafeaspb.Occurrence, string, error) { + resp := &grafeaspb.ListNoteOccurrencesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/occurrences", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOccurrences(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetVulnerabilityOccurrencesSummary gets a summary of the number and severity of occurrences. +func (c *grafeasV1Beta1RESTClient) GetVulnerabilityOccurrencesSummary(ctx context.Context, req *grafeaspb.GetVulnerabilityOccurrencesSummaryRequest, opts ...gax.CallOption) (*grafeaspb.VulnerabilityOccurrencesSummary, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/occurrences:vulnerabilitySummary", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetVulnerabilityOccurrencesSummary[0:len((*c.CallOptions).GetVulnerabilityOccurrencesSummary):len((*c.CallOptions).GetVulnerabilityOccurrencesSummary)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &grafeaspb.VulnerabilityOccurrencesSummary{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // NoteIterator manages a stream of *grafeaspb.Note. type NoteIterator struct { items []*grafeaspb.Note diff --git a/containeranalysis/apiv1beta1/grafeas_v1_beta1_client_example_test.go b/containeranalysis/apiv1beta1/grafeas_v1_beta1_client_example_test.go index 1337acbd210c..c35c88b10298 100644 --- a/containeranalysis/apiv1beta1/grafeas_v1_beta1_client_example_test.go +++ b/containeranalysis/apiv1beta1/grafeas_v1_beta1_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewGrafeasV1Beta1Client() { _ = c } +func ExampleNewGrafeasV1Beta1RESTClient() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1RESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleGrafeasV1Beta1Client_GetOccurrence() { ctx := context.Background() c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) diff --git a/dataflow/apiv1beta3/doc.go b/dataflow/apiv1beta3/doc.go index 74b0caea5e60..3895a70c8bc8 100644 --- a/dataflow/apiv1beta3/doc.go +++ b/dataflow/apiv1beta3/doc.go @@ -71,6 +71,8 @@ package dataflow // import "cloud.google.com/go/dataflow/apiv1beta3" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -162,3 +164,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/dataflow/apiv1beta3/flex_templates_client.go b/dataflow/apiv1beta3/flex_templates_client.go index 001b08ec3219..3758cbecf3cf 100644 --- a/dataflow/apiv1beta3/flex_templates_client.go +++ b/dataflow/apiv1beta3/flex_templates_client.go @@ -17,18 +17,24 @@ package dataflow import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" dataflowpb "google.golang.org/genproto/googleapis/dataflow/v1beta3" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newFlexTemplatesClientHook clientHook @@ -56,6 +62,12 @@ func defaultFlexTemplatesCallOptions() *FlexTemplatesCallOptions { } } +func defaultFlexTemplatesRESTCallOptions() *FlexTemplatesCallOptions { + return &FlexTemplatesCallOptions{ + LaunchFlexTemplate: []gax.CallOption{}, + } +} + // internalFlexTemplatesClient is an interface that defines the methods available from Dataflow API. type internalFlexTemplatesClient interface { Close() error @@ -183,6 +195,74 @@ func (c *flexTemplatesGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type flexTemplatesRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing FlexTemplatesClient + CallOptions **FlexTemplatesCallOptions +} + +// NewFlexTemplatesRESTClient creates a new flex templates service rest client. +// +// Provides a service for Flex templates. This feature is not ready yet. +func NewFlexTemplatesRESTClient(ctx context.Context, opts ...option.ClientOption) (*FlexTemplatesClient, error) { + clientOpts := append(defaultFlexTemplatesRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultFlexTemplatesRESTCallOptions() + c := &flexTemplatesRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &FlexTemplatesClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultFlexTemplatesRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dataflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dataflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dataflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *flexTemplatesRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *flexTemplatesRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *flexTemplatesRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *flexTemplatesGRPCClient) LaunchFlexTemplate(ctx context.Context, req *dataflowpb.LaunchFlexTemplateRequest, opts ...gax.CallOption) (*dataflowpb.LaunchFlexTemplateResponse, error) { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()))) @@ -199,3 +279,62 @@ func (c *flexTemplatesGRPCClient) LaunchFlexTemplate(ctx context.Context, req *d } return resp, nil } + +// LaunchFlexTemplate launch a job with a FlexTemplate. +func (c *flexTemplatesRESTClient) LaunchFlexTemplate(ctx context.Context, req *dataflowpb.LaunchFlexTemplateRequest, opts ...gax.CallOption) (*dataflowpb.LaunchFlexTemplateResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/flexTemplates:launch", req.GetProjectId(), req.GetLocation()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).LaunchFlexTemplate[0:len((*c.CallOptions).LaunchFlexTemplate):len((*c.CallOptions).LaunchFlexTemplate)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataflowpb.LaunchFlexTemplateResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/dataflow/apiv1beta3/flex_templates_client_example_test.go b/dataflow/apiv1beta3/flex_templates_client_example_test.go index 482d733b5edf..436d5940a7b2 100644 --- a/dataflow/apiv1beta3/flex_templates_client_example_test.go +++ b/dataflow/apiv1beta3/flex_templates_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewFlexTemplatesClient() { _ = c } +func ExampleNewFlexTemplatesRESTClient() { + ctx := context.Background() + c, err := dataflow.NewFlexTemplatesRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleFlexTemplatesClient_LaunchFlexTemplate() { ctx := context.Background() c, err := dataflow.NewFlexTemplatesClient(ctx) diff --git a/dataflow/apiv1beta3/gapic_metadata.json b/dataflow/apiv1beta3/gapic_metadata.json index 9dcbc9db6707..c4fddfa8e0b0 100644 --- a/dataflow/apiv1beta3/gapic_metadata.json +++ b/dataflow/apiv1beta3/gapic_metadata.json @@ -16,6 +16,16 @@ ] } } + }, + "rest": { + "libraryClient": "FlexTemplatesClient", + "rpcs": { + "LaunchFlexTemplate": { + "methods": [ + "LaunchFlexTemplate" + ] + } + } } } }, @@ -60,6 +70,46 @@ ] } } + }, + "rest": { + "libraryClient": "JobsV1Beta3Client", + "rpcs": { + "AggregatedListJobs": { + "methods": [ + "AggregatedListJobs" + ] + }, + "CheckActiveJobs": { + "methods": [ + "CheckActiveJobs" + ] + }, + "CreateJob": { + "methods": [ + "CreateJob" + ] + }, + "GetJob": { + "methods": [ + "GetJob" + ] + }, + "ListJobs": { + "methods": [ + "ListJobs" + ] + }, + "SnapshotJob": { + "methods": [ + "SnapshotJob" + ] + }, + "UpdateJob": { + "methods": [ + "UpdateJob" + ] + } + } } } }, @@ -74,6 +124,16 @@ ] } } + }, + "rest": { + "libraryClient": "MessagesV1Beta3Client", + "rpcs": { + "ListJobMessages": { + "methods": [ + "ListJobMessages" + ] + } + } } } }, @@ -98,6 +158,26 @@ ] } } + }, + "rest": { + "libraryClient": "MetricsV1Beta3Client", + "rpcs": { + "GetJobExecutionDetails": { + "methods": [ + "GetJobExecutionDetails" + ] + }, + "GetJobMetrics": { + "methods": [ + "GetJobMetrics" + ] + }, + "GetStageExecutionDetails": { + "methods": [ + "GetStageExecutionDetails" + ] + } + } } } }, @@ -122,6 +202,26 @@ ] } } + }, + "rest": { + "libraryClient": "SnapshotsV1Beta3Client", + "rpcs": { + "DeleteSnapshot": { + "methods": [ + "DeleteSnapshot" + ] + }, + "GetSnapshot": { + "methods": [ + "GetSnapshot" + ] + }, + "ListSnapshots": { + "methods": [ + "ListSnapshots" + ] + } + } } } }, @@ -146,6 +246,26 @@ ] } } + }, + "rest": { + "libraryClient": "TemplatesClient", + "rpcs": { + "CreateJobFromTemplate": { + "methods": [ + "CreateJobFromTemplate" + ] + }, + "GetTemplate": { + "methods": [ + "GetTemplate" + ] + }, + "LaunchTemplate": { + "methods": [ + "LaunchTemplate" + ] + } + } } } } diff --git a/dataflow/apiv1beta3/jobs_v1_beta3_client.go b/dataflow/apiv1beta3/jobs_v1_beta3_client.go index eab52a44e388..f5e99e8f7dfb 100644 --- a/dataflow/apiv1beta3/jobs_v1_beta3_client.go +++ b/dataflow/apiv1beta3/jobs_v1_beta3_client.go @@ -17,20 +17,26 @@ package dataflow import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" dataflowpb "google.golang.org/genproto/googleapis/dataflow/v1beta3" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -71,6 +77,18 @@ func defaultJobsV1Beta3CallOptions() *JobsV1Beta3CallOptions { } } +func defaultJobsV1Beta3RESTCallOptions() *JobsV1Beta3CallOptions { + return &JobsV1Beta3CallOptions{ + CreateJob: []gax.CallOption{}, + GetJob: []gax.CallOption{}, + UpdateJob: []gax.CallOption{}, + ListJobs: []gax.CallOption{}, + AggregatedListJobs: []gax.CallOption{}, + CheckActiveJobs: []gax.CallOption{}, + SnapshotJob: []gax.CallOption{}, + } +} + // internalJobsV1Beta3Client is an interface that defines the methods available from Dataflow API. type internalJobsV1Beta3Client interface { Close() error @@ -261,6 +279,75 @@ func (c *jobsV1Beta3GRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type jobsV1Beta3RESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing JobsV1Beta3Client + CallOptions **JobsV1Beta3CallOptions +} + +// NewJobsV1Beta3RESTClient creates a new jobs v1 beta3 rest client. +// +// Provides a method to create and modify Google Cloud Dataflow jobs. +// A Job is a multi-stage computation graph run by the Cloud Dataflow service. +func NewJobsV1Beta3RESTClient(ctx context.Context, opts ...option.ClientOption) (*JobsV1Beta3Client, error) { + clientOpts := append(defaultJobsV1Beta3RESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultJobsV1Beta3RESTCallOptions() + c := &jobsV1Beta3RESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &JobsV1Beta3Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultJobsV1Beta3RESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dataflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dataflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dataflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *jobsV1Beta3RESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *jobsV1Beta3RESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *jobsV1Beta3RESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *jobsV1Beta3GRPCClient) CreateJob(ctx context.Context, req *dataflowpb.CreateJobRequest, opts ...gax.CallOption) (*dataflowpb.Job, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -459,6 +546,527 @@ func (c *jobsV1Beta3GRPCClient) SnapshotJob(ctx context.Context, req *dataflowpb return resp, nil } +// CreateJob creates a Cloud Dataflow job. +// +// To create a job, we recommend using projects.locations.jobs.create with a +// [regional endpoint] +// (https://cloud.google.com/dataflow/docs/concepts/regional-endpoints (at https://cloud.google.com/dataflow/docs/concepts/regional-endpoints)). Using +// projects.jobs.create is not recommended, as your job will always start +// in us-central1. +func (c *jobsV1Beta3RESTClient) CreateJob(ctx context.Context, req *dataflowpb.CreateJobRequest, opts ...gax.CallOption) (*dataflowpb.Job, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetJob() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/jobs", req.GetProjectId(), req.GetLocation()) + + params := url.Values{} + if req.GetReplaceJobId() != "" { + params.Add("replaceJobId", fmt.Sprintf("%v", req.GetReplaceJobId())) + } + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateJob[0:len((*c.CallOptions).CreateJob):len((*c.CallOptions).CreateJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataflowpb.Job{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetJob gets the state of the specified Cloud Dataflow job. +// +// To get the state of a job, we recommend using projects.locations.jobs.get +// with a [regional endpoint] +// (https://cloud.google.com/dataflow/docs/concepts/regional-endpoints (at https://cloud.google.com/dataflow/docs/concepts/regional-endpoints)). Using +// projects.jobs.get is not recommended, as you can only get the state of +// jobs that are running in us-central1. +func (c *jobsV1Beta3RESTClient) GetJob(ctx context.Context, req *dataflowpb.GetJobRequest, opts ...gax.CallOption) (*dataflowpb.Job, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/jobs/%v", req.GetProjectId(), req.GetLocation(), req.GetJobId()) + + params := url.Values{} + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()), "job_id", url.QueryEscape(req.GetJobId()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetJob[0:len((*c.CallOptions).GetJob):len((*c.CallOptions).GetJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataflowpb.Job{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateJob updates the state of an existing Cloud Dataflow job. +// +// To update the state of an existing job, we recommend using +// projects.locations.jobs.update with a [regional endpoint] +// (https://cloud.google.com/dataflow/docs/concepts/regional-endpoints (at https://cloud.google.com/dataflow/docs/concepts/regional-endpoints)). Using +// projects.jobs.update is not recommended, as you can only update the state +// of jobs that are running in us-central1. +func (c *jobsV1Beta3RESTClient) UpdateJob(ctx context.Context, req *dataflowpb.UpdateJobRequest, opts ...gax.CallOption) (*dataflowpb.Job, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetJob() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/jobs/%v", req.GetProjectId(), req.GetLocation(), req.GetJobId()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()), "job_id", url.QueryEscape(req.GetJobId()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateJob[0:len((*c.CallOptions).UpdateJob):len((*c.CallOptions).UpdateJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataflowpb.Job{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PUT", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListJobs list the jobs of a project. +// +// To list the jobs of a project in a region, we recommend using +// projects.locations.jobs.list with a [regional endpoint] +// (https://cloud.google.com/dataflow/docs/concepts/regional-endpoints (at https://cloud.google.com/dataflow/docs/concepts/regional-endpoints)). To +// list the all jobs across all regions, use projects.jobs.aggregated. Using +// projects.jobs.list is not recommended, as you can only get the list of +// jobs that are running in us-central1. +func (c *jobsV1Beta3RESTClient) ListJobs(ctx context.Context, req *dataflowpb.ListJobsRequest, opts ...gax.CallOption) *JobIterator { + it := &JobIterator{} + req = proto.Clone(req).(*dataflowpb.ListJobsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataflowpb.Job, string, error) { + resp := &dataflowpb.ListJobsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/jobs", req.GetProjectId(), req.GetLocation()) + + params := url.Values{} + if req.GetFilter() != 0 { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetJobs(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// AggregatedListJobs list the jobs of a project across all regions. +func (c *jobsV1Beta3RESTClient) AggregatedListJobs(ctx context.Context, req *dataflowpb.ListJobsRequest, opts ...gax.CallOption) *JobIterator { + it := &JobIterator{} + req = proto.Clone(req).(*dataflowpb.ListJobsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataflowpb.Job, string, error) { + resp := &dataflowpb.ListJobsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/jobs:aggregated", req.GetProjectId()) + + params := url.Values{} + if req.GetFilter() != 0 { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetLocation() != "" { + params.Add("location", fmt.Sprintf("%v", req.GetLocation())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetJobs(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CheckActiveJobs check for existence of active jobs in the given project across all regions. +func (c *jobsV1Beta3RESTClient) CheckActiveJobs(ctx context.Context, req *dataflowpb.CheckActiveJobsRequest, opts ...gax.CallOption) (*dataflowpb.CheckActiveJobsResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("") + + params := url.Values{} + if req.GetProjectId() != "" { + params.Add("projectId", fmt.Sprintf("%v", req.GetProjectId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CheckActiveJobs[0:len((*c.CallOptions).CheckActiveJobs):len((*c.CallOptions).CheckActiveJobs)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataflowpb.CheckActiveJobsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// SnapshotJob snapshot the state of a streaming job. +func (c *jobsV1Beta3RESTClient) SnapshotJob(ctx context.Context, req *dataflowpb.SnapshotJobRequest, opts ...gax.CallOption) (*dataflowpb.Snapshot, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/jobs/%v:snapshot", req.GetProjectId(), req.GetLocation(), req.GetJobId()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()), "job_id", url.QueryEscape(req.GetJobId()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SnapshotJob[0:len((*c.CallOptions).SnapshotJob):len((*c.CallOptions).SnapshotJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataflowpb.Snapshot{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // JobIterator manages a stream of *dataflowpb.Job. type JobIterator struct { items []*dataflowpb.Job diff --git a/dataflow/apiv1beta3/jobs_v1_beta3_client_example_test.go b/dataflow/apiv1beta3/jobs_v1_beta3_client_example_test.go index 22b289f2fc9d..8ff7c00f8cef 100644 --- a/dataflow/apiv1beta3/jobs_v1_beta3_client_example_test.go +++ b/dataflow/apiv1beta3/jobs_v1_beta3_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewJobsV1Beta3Client() { _ = c } +func ExampleNewJobsV1Beta3RESTClient() { + ctx := context.Background() + c, err := dataflow.NewJobsV1Beta3RESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleJobsV1Beta3Client_CreateJob() { ctx := context.Background() c, err := dataflow.NewJobsV1Beta3Client(ctx) diff --git a/dataflow/apiv1beta3/messages_v1_beta3_client.go b/dataflow/apiv1beta3/messages_v1_beta3_client.go index c3db169c11cf..4c144a458ba2 100644 --- a/dataflow/apiv1beta3/messages_v1_beta3_client.go +++ b/dataflow/apiv1beta3/messages_v1_beta3_client.go @@ -19,17 +19,22 @@ package dataflow import ( "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" dataflowpb "google.golang.org/genproto/googleapis/dataflow/v1beta3" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -58,6 +63,12 @@ func defaultMessagesV1Beta3CallOptions() *MessagesV1Beta3CallOptions { } } +func defaultMessagesV1Beta3RESTCallOptions() *MessagesV1Beta3CallOptions { + return &MessagesV1Beta3CallOptions{ + ListJobMessages: []gax.CallOption{}, + } +} + // internalMessagesV1Beta3Client is an interface that defines the methods available from Dataflow API. type internalMessagesV1Beta3Client interface { Close() error @@ -193,6 +204,75 @@ func (c *messagesV1Beta3GRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type messagesV1Beta3RESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing MessagesV1Beta3Client + CallOptions **MessagesV1Beta3CallOptions +} + +// NewMessagesV1Beta3RESTClient creates a new messages v1 beta3 rest client. +// +// The Dataflow Messages API is used for monitoring the progress of +// Dataflow jobs. +func NewMessagesV1Beta3RESTClient(ctx context.Context, opts ...option.ClientOption) (*MessagesV1Beta3Client, error) { + clientOpts := append(defaultMessagesV1Beta3RESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultMessagesV1Beta3RESTCallOptions() + c := &messagesV1Beta3RESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &MessagesV1Beta3Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultMessagesV1Beta3RESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dataflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dataflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dataflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *messagesV1Beta3RESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *messagesV1Beta3RESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *messagesV1Beta3RESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *messagesV1Beta3GRPCClient) ListJobMessages(ctx context.Context, req *dataflowpb.ListJobMessagesRequest, opts ...gax.CallOption) *JobMessageIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()), "job_id", url.QueryEscape(req.GetJobId()))) @@ -238,6 +318,114 @@ func (c *messagesV1Beta3GRPCClient) ListJobMessages(ctx context.Context, req *da return it } +// ListJobMessages request the job status. +// +// To request the status of a job, we recommend using +// projects.locations.jobs.messages.list with a [regional endpoint] +// (https://cloud.google.com/dataflow/docs/concepts/regional-endpoints (at https://cloud.google.com/dataflow/docs/concepts/regional-endpoints)). Using +// projects.jobs.messages.list is not recommended, as you can only request +// the status of jobs that are running in us-central1. +func (c *messagesV1Beta3RESTClient) ListJobMessages(ctx context.Context, req *dataflowpb.ListJobMessagesRequest, opts ...gax.CallOption) *JobMessageIterator { + it := &JobMessageIterator{} + req = proto.Clone(req).(*dataflowpb.ListJobMessagesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataflowpb.JobMessage, string, error) { + resp := &dataflowpb.ListJobMessagesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/jobs/%v/messages", req.GetProjectId(), req.GetLocation(), req.GetJobId()) + + params := url.Values{} + if req.GetEndTime().GetNanos() != 0 { + params.Add("endTime.nanos", fmt.Sprintf("%v", req.GetEndTime().GetNanos())) + } + if req.GetEndTime().GetSeconds() != 0 { + params.Add("endTime.seconds", fmt.Sprintf("%v", req.GetEndTime().GetSeconds())) + } + if req.GetMinimumImportance() != 0 { + params.Add("minimumImportance", fmt.Sprintf("%v", req.GetMinimumImportance())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetStartTime().GetNanos() != 0 { + params.Add("startTime.nanos", fmt.Sprintf("%v", req.GetStartTime().GetNanos())) + } + if req.GetStartTime().GetSeconds() != 0 { + params.Add("startTime.seconds", fmt.Sprintf("%v", req.GetStartTime().GetSeconds())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetJobMessages(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // JobMessageIterator manages a stream of *dataflowpb.JobMessage. type JobMessageIterator struct { items []*dataflowpb.JobMessage diff --git a/dataflow/apiv1beta3/messages_v1_beta3_client_example_test.go b/dataflow/apiv1beta3/messages_v1_beta3_client_example_test.go index d03feaae4d45..3a5a3b2d803e 100644 --- a/dataflow/apiv1beta3/messages_v1_beta3_client_example_test.go +++ b/dataflow/apiv1beta3/messages_v1_beta3_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewMessagesV1Beta3Client() { _ = c } +func ExampleNewMessagesV1Beta3RESTClient() { + ctx := context.Background() + c, err := dataflow.NewMessagesV1Beta3RESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleMessagesV1Beta3Client_ListJobMessages() { ctx := context.Background() c, err := dataflow.NewMessagesV1Beta3Client(ctx) diff --git a/dataflow/apiv1beta3/metrics_v1_beta3_client.go b/dataflow/apiv1beta3/metrics_v1_beta3_client.go index c75b31adbe68..b3a1ac3ca697 100644 --- a/dataflow/apiv1beta3/metrics_v1_beta3_client.go +++ b/dataflow/apiv1beta3/metrics_v1_beta3_client.go @@ -19,18 +19,23 @@ package dataflow import ( "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" dataflowpb "google.golang.org/genproto/googleapis/dataflow/v1beta3" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -63,6 +68,14 @@ func defaultMetricsV1Beta3CallOptions() *MetricsV1Beta3CallOptions { } } +func defaultMetricsV1Beta3RESTCallOptions() *MetricsV1Beta3CallOptions { + return &MetricsV1Beta3CallOptions{ + GetJobMetrics: []gax.CallOption{}, + GetJobExecutionDetails: []gax.CallOption{}, + GetStageExecutionDetails: []gax.CallOption{}, + } +} + // internalMetricsV1Beta3Client is an interface that defines the methods available from Dataflow API. type internalMetricsV1Beta3Client interface { Close() error @@ -215,6 +228,75 @@ func (c *metricsV1Beta3GRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type metricsV1Beta3RESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing MetricsV1Beta3Client + CallOptions **MetricsV1Beta3CallOptions +} + +// NewMetricsV1Beta3RESTClient creates a new metrics v1 beta3 rest client. +// +// The Dataflow Metrics API lets you monitor the progress of Dataflow +// jobs. +func NewMetricsV1Beta3RESTClient(ctx context.Context, opts ...option.ClientOption) (*MetricsV1Beta3Client, error) { + clientOpts := append(defaultMetricsV1Beta3RESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultMetricsV1Beta3RESTCallOptions() + c := &metricsV1Beta3RESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &MetricsV1Beta3Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultMetricsV1Beta3RESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dataflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dataflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dataflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *metricsV1Beta3RESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *metricsV1Beta3RESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *metricsV1Beta3RESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *metricsV1Beta3GRPCClient) GetJobMetrics(ctx context.Context, req *dataflowpb.GetJobMetricsRequest, opts ...gax.CallOption) (*dataflowpb.JobMetrics, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -327,6 +409,266 @@ func (c *metricsV1Beta3GRPCClient) GetStageExecutionDetails(ctx context.Context, return it } +// GetJobMetrics request the job status. +// +// To request the status of a job, we recommend using +// projects.locations.jobs.getMetrics with a [regional endpoint] +// (https://cloud.google.com/dataflow/docs/concepts/regional-endpoints (at https://cloud.google.com/dataflow/docs/concepts/regional-endpoints)). Using +// projects.jobs.getMetrics is not recommended, as you can only request the +// status of jobs that are running in us-central1. +func (c *metricsV1Beta3RESTClient) GetJobMetrics(ctx context.Context, req *dataflowpb.GetJobMetricsRequest, opts ...gax.CallOption) (*dataflowpb.JobMetrics, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/jobs/%v/metrics", req.GetProjectId(), req.GetLocation(), req.GetJobId()) + + params := url.Values{} + if req.GetStartTime().GetNanos() != 0 { + params.Add("startTime.nanos", fmt.Sprintf("%v", req.GetStartTime().GetNanos())) + } + if req.GetStartTime().GetSeconds() != 0 { + params.Add("startTime.seconds", fmt.Sprintf("%v", req.GetStartTime().GetSeconds())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()), "job_id", url.QueryEscape(req.GetJobId()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetJobMetrics[0:len((*c.CallOptions).GetJobMetrics):len((*c.CallOptions).GetJobMetrics)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataflowpb.JobMetrics{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetJobExecutionDetails request detailed information about the execution status of the job. +// +// EXPERIMENTAL. This API is subject to change or removal without notice. +func (c *metricsV1Beta3RESTClient) GetJobExecutionDetails(ctx context.Context, req *dataflowpb.GetJobExecutionDetailsRequest, opts ...gax.CallOption) *StageSummaryIterator { + it := &StageSummaryIterator{} + req = proto.Clone(req).(*dataflowpb.GetJobExecutionDetailsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataflowpb.StageSummary, string, error) { + resp := &dataflowpb.JobExecutionDetails{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/jobs/%v/executionDetails", req.GetProjectId(), req.GetLocation(), req.GetJobId()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetStages(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetStageExecutionDetails request detailed information about the execution status of a stage of the +// job. +// +// EXPERIMENTAL. This API is subject to change or removal without notice. +func (c *metricsV1Beta3RESTClient) GetStageExecutionDetails(ctx context.Context, req *dataflowpb.GetStageExecutionDetailsRequest, opts ...gax.CallOption) *WorkerDetailsIterator { + it := &WorkerDetailsIterator{} + req = proto.Clone(req).(*dataflowpb.GetStageExecutionDetailsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataflowpb.WorkerDetails, string, error) { + resp := &dataflowpb.StageExecutionDetails{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/jobs/%v/stages/%v/executionDetails", req.GetProjectId(), req.GetLocation(), req.GetJobId(), req.GetStageId()) + + params := url.Values{} + if req.GetEndTime().GetNanos() != 0 { + params.Add("endTime.nanos", fmt.Sprintf("%v", req.GetEndTime().GetNanos())) + } + if req.GetEndTime().GetSeconds() != 0 { + params.Add("endTime.seconds", fmt.Sprintf("%v", req.GetEndTime().GetSeconds())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetStartTime().GetNanos() != 0 { + params.Add("startTime.nanos", fmt.Sprintf("%v", req.GetStartTime().GetNanos())) + } + if req.GetStartTime().GetSeconds() != 0 { + params.Add("startTime.seconds", fmt.Sprintf("%v", req.GetStartTime().GetSeconds())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetWorkers(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // StageSummaryIterator manages a stream of *dataflowpb.StageSummary. type StageSummaryIterator struct { items []*dataflowpb.StageSummary diff --git a/dataflow/apiv1beta3/metrics_v1_beta3_client_example_test.go b/dataflow/apiv1beta3/metrics_v1_beta3_client_example_test.go index 7a994eb7fba4..e4f8e5eeae0b 100644 --- a/dataflow/apiv1beta3/metrics_v1_beta3_client_example_test.go +++ b/dataflow/apiv1beta3/metrics_v1_beta3_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewMetricsV1Beta3Client() { _ = c } +func ExampleNewMetricsV1Beta3RESTClient() { + ctx := context.Background() + c, err := dataflow.NewMetricsV1Beta3RESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleMetricsV1Beta3Client_GetJobMetrics() { ctx := context.Background() c, err := dataflow.NewMetricsV1Beta3Client(ctx) diff --git a/dataflow/apiv1beta3/snapshots_v1_beta3_client.go b/dataflow/apiv1beta3/snapshots_v1_beta3_client.go index 856bc7373158..9081bd5b14d8 100644 --- a/dataflow/apiv1beta3/snapshots_v1_beta3_client.go +++ b/dataflow/apiv1beta3/snapshots_v1_beta3_client.go @@ -19,17 +19,22 @@ package dataflow import ( "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" dataflowpb "google.golang.org/genproto/googleapis/dataflow/v1beta3" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newSnapshotsV1Beta3ClientHook clientHook @@ -61,6 +66,14 @@ func defaultSnapshotsV1Beta3CallOptions() *SnapshotsV1Beta3CallOptions { } } +func defaultSnapshotsV1Beta3RESTCallOptions() *SnapshotsV1Beta3CallOptions { + return &SnapshotsV1Beta3CallOptions{ + GetSnapshot: []gax.CallOption{}, + DeleteSnapshot: []gax.CallOption{}, + ListSnapshots: []gax.CallOption{}, + } +} + // internalSnapshotsV1Beta3Client is an interface that defines the methods available from Dataflow API. type internalSnapshotsV1Beta3Client interface { Close() error @@ -200,6 +213,74 @@ func (c *snapshotsV1Beta3GRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type snapshotsV1Beta3RESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing SnapshotsV1Beta3Client + CallOptions **SnapshotsV1Beta3CallOptions +} + +// NewSnapshotsV1Beta3RESTClient creates a new snapshots v1 beta3 rest client. +// +// Provides methods to manage snapshots of Google Cloud Dataflow jobs. +func NewSnapshotsV1Beta3RESTClient(ctx context.Context, opts ...option.ClientOption) (*SnapshotsV1Beta3Client, error) { + clientOpts := append(defaultSnapshotsV1Beta3RESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultSnapshotsV1Beta3RESTCallOptions() + c := &snapshotsV1Beta3RESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &SnapshotsV1Beta3Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultSnapshotsV1Beta3RESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dataflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dataflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dataflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *snapshotsV1Beta3RESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *snapshotsV1Beta3RESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *snapshotsV1Beta3RESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *snapshotsV1Beta3GRPCClient) GetSnapshot(ctx context.Context, req *dataflowpb.GetSnapshotRequest, opts ...gax.CallOption) (*dataflowpb.Snapshot, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -265,3 +346,162 @@ func (c *snapshotsV1Beta3GRPCClient) ListSnapshots(ctx context.Context, req *dat } return resp, nil } + +// GetSnapshot gets information about a snapshot. +func (c *snapshotsV1Beta3RESTClient) GetSnapshot(ctx context.Context, req *dataflowpb.GetSnapshotRequest, opts ...gax.CallOption) (*dataflowpb.Snapshot, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/snapshots/%v", req.GetProjectId(), req.GetLocation(), req.GetSnapshotId()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()), "snapshot_id", url.QueryEscape(req.GetSnapshotId()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetSnapshot[0:len((*c.CallOptions).GetSnapshot):len((*c.CallOptions).GetSnapshot)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataflowpb.Snapshot{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteSnapshot deletes a snapshot. +func (c *snapshotsV1Beta3RESTClient) DeleteSnapshot(ctx context.Context, req *dataflowpb.DeleteSnapshotRequest, opts ...gax.CallOption) (*dataflowpb.DeleteSnapshotResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/snapshots/%v", req.GetProjectId(), req.GetLocation(), req.GetSnapshotId()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()), "snapshot_id", url.QueryEscape(req.GetSnapshotId()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).DeleteSnapshot[0:len((*c.CallOptions).DeleteSnapshot):len((*c.CallOptions).DeleteSnapshot)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataflowpb.DeleteSnapshotResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListSnapshots lists snapshots. +func (c *snapshotsV1Beta3RESTClient) ListSnapshots(ctx context.Context, req *dataflowpb.ListSnapshotsRequest, opts ...gax.CallOption) (*dataflowpb.ListSnapshotsResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/jobs/%v/snapshots", req.GetProjectId(), req.GetLocation(), req.GetJobId()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()), "job_id", url.QueryEscape(req.GetJobId()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ListSnapshots[0:len((*c.CallOptions).ListSnapshots):len((*c.CallOptions).ListSnapshots)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataflowpb.ListSnapshotsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/dataflow/apiv1beta3/snapshots_v1_beta3_client_example_test.go b/dataflow/apiv1beta3/snapshots_v1_beta3_client_example_test.go index 5e3233116355..e39114790df9 100644 --- a/dataflow/apiv1beta3/snapshots_v1_beta3_client_example_test.go +++ b/dataflow/apiv1beta3/snapshots_v1_beta3_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewSnapshotsV1Beta3Client() { _ = c } +func ExampleNewSnapshotsV1Beta3RESTClient() { + ctx := context.Background() + c, err := dataflow.NewSnapshotsV1Beta3RESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleSnapshotsV1Beta3Client_GetSnapshot() { ctx := context.Background() c, err := dataflow.NewSnapshotsV1Beta3Client(ctx) diff --git a/dataflow/apiv1beta3/templates_client.go b/dataflow/apiv1beta3/templates_client.go index 101c69ccb383..19781ed33534 100644 --- a/dataflow/apiv1beta3/templates_client.go +++ b/dataflow/apiv1beta3/templates_client.go @@ -17,19 +17,25 @@ package dataflow import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" dataflowpb "google.golang.org/genproto/googleapis/dataflow/v1beta3" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newTemplatesClientHook clientHook @@ -61,6 +67,14 @@ func defaultTemplatesCallOptions() *TemplatesCallOptions { } } +func defaultTemplatesRESTCallOptions() *TemplatesCallOptions { + return &TemplatesCallOptions{ + CreateJobFromTemplate: []gax.CallOption{}, + LaunchTemplate: []gax.CallOption{}, + GetTemplate: []gax.CallOption{}, + } +} + // internalTemplatesClient is an interface that defines the methods available from Dataflow API. type internalTemplatesClient interface { Close() error @@ -200,6 +214,74 @@ func (c *templatesGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type templatesRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing TemplatesClient + CallOptions **TemplatesCallOptions +} + +// NewTemplatesRESTClient creates a new templates service rest client. +// +// Provides a method to create Cloud Dataflow jobs from templates. +func NewTemplatesRESTClient(ctx context.Context, opts ...option.ClientOption) (*TemplatesClient, error) { + clientOpts := append(defaultTemplatesRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultTemplatesRESTCallOptions() + c := &templatesRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &TemplatesClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultTemplatesRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dataflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dataflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dataflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *templatesRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *templatesRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *templatesRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *templatesGRPCClient) CreateJobFromTemplate(ctx context.Context, req *dataflowpb.CreateJobFromTemplateRequest, opts ...gax.CallOption) (*dataflowpb.Job, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -265,3 +347,201 @@ func (c *templatesGRPCClient) GetTemplate(ctx context.Context, req *dataflowpb.G } return resp, nil } + +// CreateJobFromTemplate creates a Cloud Dataflow job from a template. +func (c *templatesRESTClient) CreateJobFromTemplate(ctx context.Context, req *dataflowpb.CreateJobFromTemplateRequest, opts ...gax.CallOption) (*dataflowpb.Job, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/templates", req.GetProjectId(), req.GetLocation()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateJobFromTemplate[0:len((*c.CallOptions).CreateJobFromTemplate):len((*c.CallOptions).CreateJobFromTemplate)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataflowpb.Job{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// LaunchTemplate launch a template. +func (c *templatesRESTClient) LaunchTemplate(ctx context.Context, req *dataflowpb.LaunchTemplateRequest, opts ...gax.CallOption) (*dataflowpb.LaunchTemplateResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetLaunchParameters() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/templates:launch", req.GetProjectId(), req.GetLocation()) + + params := url.Values{} + if req.GetDynamicTemplate().GetGcsPath() != "" { + params.Add("dynamicTemplate.gcsPath", fmt.Sprintf("%v", req.GetDynamicTemplate().GetGcsPath())) + } + if req.GetDynamicTemplate().GetStagingLocation() != "" { + params.Add("dynamicTemplate.stagingLocation", fmt.Sprintf("%v", req.GetDynamicTemplate().GetStagingLocation())) + } + if req.GetGcsPath() != "" { + params.Add("gcsPath", fmt.Sprintf("%v", req.GetGcsPath())) + } + if req.GetValidateOnly() { + params.Add("validateOnly", fmt.Sprintf("%v", req.GetValidateOnly())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).LaunchTemplate[0:len((*c.CallOptions).LaunchTemplate):len((*c.CallOptions).LaunchTemplate)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataflowpb.LaunchTemplateResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetTemplate get the template associated with a template. +func (c *templatesRESTClient) GetTemplate(ctx context.Context, req *dataflowpb.GetTemplateRequest, opts ...gax.CallOption) (*dataflowpb.GetTemplateResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1b3/projects/%v/locations/%v/templates:get", req.GetProjectId(), req.GetLocation()) + + params := url.Values{} + if req.GetGcsPath() != "" { + params.Add("gcsPath", fmt.Sprintf("%v", req.GetGcsPath())) + } + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v&%s=%v", "project_id", url.QueryEscape(req.GetProjectId()), "location", url.QueryEscape(req.GetLocation()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetTemplate[0:len((*c.CallOptions).GetTemplate):len((*c.CallOptions).GetTemplate)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataflowpb.GetTemplateResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/dataflow/apiv1beta3/templates_client_example_test.go b/dataflow/apiv1beta3/templates_client_example_test.go index 8f6073ed278c..eb13dd038d2e 100644 --- a/dataflow/apiv1beta3/templates_client_example_test.go +++ b/dataflow/apiv1beta3/templates_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewTemplatesClient() { _ = c } +func ExampleNewTemplatesRESTClient() { + ctx := context.Background() + c, err := dataflow.NewTemplatesRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleTemplatesClient_CreateJobFromTemplate() { ctx := context.Background() c, err := dataflow.NewTemplatesClient(ctx) diff --git a/dataqna/apiv1alpha/auto_suggestion_client.go b/dataqna/apiv1alpha/auto_suggestion_client.go index 3f6f4532668d..8accbd5c0d4e 100644 --- a/dataqna/apiv1alpha/auto_suggestion_client.go +++ b/dataqna/apiv1alpha/auto_suggestion_client.go @@ -17,19 +17,25 @@ package dataqna import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" dataqnapb "google.golang.org/genproto/googleapis/cloud/dataqna/v1alpha" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newAutoSuggestionClientHook clientHook @@ -57,6 +63,12 @@ func defaultAutoSuggestionCallOptions() *AutoSuggestionCallOptions { } } +func defaultAutoSuggestionRESTCallOptions() *AutoSuggestionCallOptions { + return &AutoSuggestionCallOptions{ + SuggestQueries: []gax.CallOption{}, + } +} + // internalAutoSuggestionClient is an interface that defines the methods available from Data QnA API. type internalAutoSuggestionClient interface { Close() error @@ -213,6 +225,88 @@ func (c *autoSuggestionGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type autoSuggestionRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing AutoSuggestionClient + CallOptions **AutoSuggestionCallOptions +} + +// NewAutoSuggestionRESTClient creates a new auto suggestion service rest client. +// +// This stateless API provides automatic suggestions for natural language +// queries for the data sources in the provided project and location. +// +// The service provides a resourceless operation suggestQueries that can be +// called to get a list of suggestions for a given incomplete query and scope +// (or list of scopes) under which the query is to be interpreted. +// +// There are two types of suggestions, ENTITY for single entity suggestions +// and TEMPLATE for full sentences. By default, both types are returned. +// +// Example Request: +// +// The service will retrieve information based on the given scope(s) and give +// suggestions based on that (e.g. “top item” for “top it” if “item” is a known +// dimension for the provided scope). +func NewAutoSuggestionRESTClient(ctx context.Context, opts ...option.ClientOption) (*AutoSuggestionClient, error) { + clientOpts := append(defaultAutoSuggestionRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultAutoSuggestionRESTCallOptions() + c := &autoSuggestionRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &AutoSuggestionClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultAutoSuggestionRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dataqna.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dataqna.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dataqna.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *autoSuggestionRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *autoSuggestionRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *autoSuggestionRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *autoSuggestionGRPCClient) SuggestQueries(ctx context.Context, req *dataqnapb.SuggestQueriesRequest, opts ...gax.CallOption) (*dataqnapb.SuggestQueriesResponse, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 2000*time.Millisecond) @@ -234,3 +328,63 @@ func (c *autoSuggestionGRPCClient) SuggestQueries(ctx context.Context, req *data } return resp, nil } + +// SuggestQueries gets a list of suggestions based on a prefix string. +// AutoSuggestion tolerance should be less than 1 second. +func (c *autoSuggestionRESTClient) SuggestQueries(ctx context.Context, req *dataqnapb.SuggestQueriesRequest, opts ...gax.CallOption) (*dataqnapb.SuggestQueriesResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v:suggestQueries", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SuggestQueries[0:len((*c.CallOptions).SuggestQueries):len((*c.CallOptions).SuggestQueries)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataqnapb.SuggestQueriesResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/dataqna/apiv1alpha/auto_suggestion_client_example_test.go b/dataqna/apiv1alpha/auto_suggestion_client_example_test.go index 4bd6d853eab8..4e524b5fefc4 100644 --- a/dataqna/apiv1alpha/auto_suggestion_client_example_test.go +++ b/dataqna/apiv1alpha/auto_suggestion_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewAutoSuggestionClient() { _ = c } +func ExampleNewAutoSuggestionRESTClient() { + ctx := context.Background() + c, err := dataqna.NewAutoSuggestionRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleAutoSuggestionClient_SuggestQueries() { ctx := context.Background() c, err := dataqna.NewAutoSuggestionClient(ctx) diff --git a/dataqna/apiv1alpha/doc.go b/dataqna/apiv1alpha/doc.go index 9cba3c666f3b..7b90fbc5d95d 100644 --- a/dataqna/apiv1alpha/doc.go +++ b/dataqna/apiv1alpha/doc.go @@ -72,6 +72,8 @@ package dataqna // import "cloud.google.com/go/dataqna/apiv1alpha" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -160,3 +162,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/dataqna/apiv1alpha/gapic_metadata.json b/dataqna/apiv1alpha/gapic_metadata.json index 5ed6988e3fa2..2a347d34b9b3 100644 --- a/dataqna/apiv1alpha/gapic_metadata.json +++ b/dataqna/apiv1alpha/gapic_metadata.json @@ -16,6 +16,16 @@ ] } } + }, + "rest": { + "libraryClient": "AutoSuggestionClient", + "rpcs": { + "SuggestQueries": { + "methods": [ + "SuggestQueries" + ] + } + } } } }, @@ -50,6 +60,36 @@ ] } } + }, + "rest": { + "libraryClient": "QuestionClient", + "rpcs": { + "CreateQuestion": { + "methods": [ + "CreateQuestion" + ] + }, + "ExecuteQuestion": { + "methods": [ + "ExecuteQuestion" + ] + }, + "GetQuestion": { + "methods": [ + "GetQuestion" + ] + }, + "GetUserFeedback": { + "methods": [ + "GetUserFeedback" + ] + }, + "UpdateUserFeedback": { + "methods": [ + "UpdateUserFeedback" + ] + } + } } } } diff --git a/dataqna/apiv1alpha/question_client.go b/dataqna/apiv1alpha/question_client.go index 630ff4957695..46dde2514f85 100644 --- a/dataqna/apiv1alpha/question_client.go +++ b/dataqna/apiv1alpha/question_client.go @@ -17,20 +17,26 @@ package dataqna import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" dataqnapb "google.golang.org/genproto/googleapis/cloud/dataqna/v1alpha" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newQuestionClientHook clientHook @@ -86,6 +92,34 @@ func defaultQuestionCallOptions() *QuestionCallOptions { } } +func defaultQuestionRESTCallOptions() *QuestionCallOptions { + return &QuestionCallOptions{ + GetQuestion: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateQuestion: []gax.CallOption{}, + ExecuteQuestion: []gax.CallOption{}, + GetUserFeedback: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateUserFeedback: []gax.CallOption{}, + } +} + // internalQuestionClient is an interface that defines the methods available from Data QnA API. type internalQuestionClient interface { Close() error @@ -266,6 +300,88 @@ func (c *questionGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type questionRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing QuestionClient + CallOptions **QuestionCallOptions +} + +// NewQuestionRESTClient creates a new question service rest client. +// +// Service to interpret natural language queries. +// The service allows to create Question resources that are interpreted and +// are filled with one or more interpretations if the question could be +// interpreted. Once a Question resource is created and has at least one +// interpretation, an interpretation can be chosen for execution, which +// triggers a query to the backend (for BigQuery, it will create a job). +// Upon successful execution of that interpretation, backend specific +// information will be returned so that the client can retrieve the results +// from the backend. +// +// The Question resources are named projects/*/locations/*/questions/*. +// +// The Question resource has a singletion sub-resource UserFeedback named +// projects/*/locations/*/questions/*/userFeedback, which allows access to +// user feedback. +func NewQuestionRESTClient(ctx context.Context, opts ...option.ClientOption) (*QuestionClient, error) { + clientOpts := append(defaultQuestionRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultQuestionRESTCallOptions() + c := &questionRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &QuestionClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultQuestionRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dataqna.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dataqna.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dataqna.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *questionRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *questionRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *questionRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *questionGRPCClient) GetQuestion(ctx context.Context, req *dataqnapb.GetQuestionRequest, opts ...gax.CallOption) (*dataqnapb.Question, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -375,3 +491,303 @@ func (c *questionGRPCClient) UpdateUserFeedback(ctx context.Context, req *dataqn } return resp, nil } + +// GetQuestion gets a previously created question. +func (c *questionRESTClient) GetQuestion(ctx context.Context, req *dataqnapb.GetQuestionRequest, opts ...gax.CallOption) (*dataqnapb.Question, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + params := url.Values{} + if req.GetReadMask().GetPaths() != nil { + params.Add("readMask.paths", fmt.Sprintf("%v", req.GetReadMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetQuestion[0:len((*c.CallOptions).GetQuestion):len((*c.CallOptions).GetQuestion)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataqnapb.Question{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateQuestion creates a question. +func (c *questionRESTClient) CreateQuestion(ctx context.Context, req *dataqnapb.CreateQuestionRequest, opts ...gax.CallOption) (*dataqnapb.Question, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetQuestion() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/questions", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateQuestion[0:len((*c.CallOptions).CreateQuestion):len((*c.CallOptions).CreateQuestion)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataqnapb.Question{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ExecuteQuestion executes an interpretation. +func (c *questionRESTClient) ExecuteQuestion(ctx context.Context, req *dataqnapb.ExecuteQuestionRequest, opts ...gax.CallOption) (*dataqnapb.Question, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v:execute", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ExecuteQuestion[0:len((*c.CallOptions).ExecuteQuestion):len((*c.CallOptions).ExecuteQuestion)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataqnapb.Question{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetUserFeedback gets previously created user feedback. +func (c *questionRESTClient) GetUserFeedback(ctx context.Context, req *dataqnapb.GetUserFeedbackRequest, opts ...gax.CallOption) (*dataqnapb.UserFeedback, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetUserFeedback[0:len((*c.CallOptions).GetUserFeedback):len((*c.CallOptions).GetUserFeedback)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataqnapb.UserFeedback{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateUserFeedback updates user feedback. This creates user feedback if there was none before +// (upsert). +func (c *questionRESTClient) UpdateUserFeedback(ctx context.Context, req *dataqnapb.UpdateUserFeedbackRequest, opts ...gax.CallOption) (*dataqnapb.UserFeedback, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetUserFeedback() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetUserFeedback().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "user_feedback.name", url.QueryEscape(req.GetUserFeedback().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateUserFeedback[0:len((*c.CallOptions).UpdateUserFeedback):len((*c.CallOptions).UpdateUserFeedback)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &dataqnapb.UserFeedback{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/dataqna/apiv1alpha/question_client_example_test.go b/dataqna/apiv1alpha/question_client_example_test.go index 32030cb26e62..3421dfd3bf69 100644 --- a/dataqna/apiv1alpha/question_client_example_test.go +++ b/dataqna/apiv1alpha/question_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewQuestionClient() { _ = c } +func ExampleNewQuestionRESTClient() { + ctx := context.Background() + c, err := dataqna.NewQuestionRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleQuestionClient_GetQuestion() { ctx := context.Background() c, err := dataqna.NewQuestionClient(ctx) diff --git a/dataqna/go.mod b/dataqna/go.mod index 6cd307b2c803..626736a6ae7e 100644 --- a/dataqna/go.mod +++ b/dataqna/go.mod @@ -8,4 +8,5 @@ require ( google.golang.org/api v0.84.0 google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad google.golang.org/grpc v1.47.0 + google.golang.org/protobuf v1.28.0 ) diff --git a/datastream/apiv1alpha1/datastream_client.go b/datastream/apiv1alpha1/datastream_client.go index 2ee02eb37063..97c9fa916340 100644 --- a/datastream/apiv1alpha1/datastream_client.go +++ b/datastream/apiv1alpha1/datastream_client.go @@ -17,24 +17,30 @@ package datastream import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" datastreampb "google.golang.org/genproto/googleapis/cloud/datastream/v1alpha1" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -213,6 +219,131 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + ListConnectionProfiles: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetConnectionProfile: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateConnectionProfile: []gax.CallOption{}, + UpdateConnectionProfile: []gax.CallOption{}, + DeleteConnectionProfile: []gax.CallOption{}, + DiscoverConnectionProfile: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListStreams: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetStream: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateStream: []gax.CallOption{}, + UpdateStream: []gax.CallOption{}, + DeleteStream: []gax.CallOption{}, + FetchErrors: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + FetchStaticIps: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreatePrivateConnection: []gax.CallOption{}, + GetPrivateConnection: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListPrivateConnections: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeletePrivateConnection: []gax.CallOption{}, + CreateRoute: []gax.CallOption{}, + GetRoute: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListRoutes: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteRoute: []gax.CallOption{}, + } +} + // internalClient is an interface that defines the methods available from Datastream API. type internalClient interface { Close() error @@ -567,6 +698,89 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new datastream rest client. +// +// Datastream service +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://datastream.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://datastream.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://datastream.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) ListConnectionProfiles(ctx context.Context, req *datastreampb.ListConnectionProfilesRequest, opts ...gax.CallOption) *ConnectionProfileIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -1166,67 +1380,1589 @@ func (c *gRPCClient) DeleteRoute(ctx context.Context, req *datastreampb.DeleteRo }, nil } -// CreateConnectionProfileOperation manages a long-running operation from CreateConnectionProfile. -type CreateConnectionProfileOperation struct { - lro *longrunning.Operation -} +// ListConnectionProfiles use this method to list connection profiles created in a project and +// location. +func (c *restClient) ListConnectionProfiles(ctx context.Context, req *datastreampb.ListConnectionProfilesRequest, opts ...gax.CallOption) *ConnectionProfileIterator { + it := &ConnectionProfileIterator{} + req = proto.Clone(req).(*datastreampb.ListConnectionProfilesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*datastreampb.ConnectionProfile, string, error) { + resp := &datastreampb.ListConnectionProfilesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/connectionProfiles", req.GetParent()) -// CreateConnectionProfileOperation returns a new CreateConnectionProfileOperation from a given name. -// The name must be that of a previously created CreateConnectionProfileOperation, possibly from a different process. -func (c *gRPCClient) CreateConnectionProfileOperation(name string) *CreateConnectionProfileOperation { - return &CreateConnectionProfileOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetOrderBy() != "" { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetConnectionProfiles(), resp.GetNextPageToken(), nil } -} -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. -// -// See documentation of Poll for error-handling information. -func (op *CreateConnectionProfileOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*datastreampb.ConnectionProfile, error) { - var resp datastreampb.ConnectionProfile - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - return &resp, nil + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it } -// Poll fetches the latest state of the long-running operation. -// -// Poll also fetches the latest metadata, which can be retrieved by Metadata. -// -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *CreateConnectionProfileOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*datastreampb.ConnectionProfile, error) { - var resp datastreampb.ConnectionProfile - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { +// GetConnectionProfile use this method to get details about a connection profile. +func (c *restClient) GetConnectionProfile(ctx context.Context, req *datastreampb.GetConnectionProfileRequest, opts ...gax.CallOption) (*datastreampb.ConnectionProfile, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - if !op.Done() { - return nil, nil + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetConnectionProfile[0:len((*c.CallOptions).GetConnectionProfile):len((*c.CallOptions).GetConnectionProfile)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &datastreampb.ConnectionProfile{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e } - return &resp, nil + return resp, nil } -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. -// If the metadata is not available, the returned metadata and error are both nil. -func (op *CreateConnectionProfileOperation) Metadata() (*datastreampb.OperationMetadata, error) { - var meta datastreampb.OperationMetadata - if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { - return nil, nil - } else if err != nil { +// CreateConnectionProfile use this method to create a connection profile in a project and location. +func (c *restClient) CreateConnectionProfile(ctx context.Context, req *datastreampb.CreateConnectionProfileRequest, opts ...gax.CallOption) (*CreateConnectionProfileOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetConnectionProfile() + jsonReq, err := m.Marshal(body) + if err != nil { return nil, err } - return &meta, nil -} -// Done reports whether the long-running operation has completed. -func (op *CreateConnectionProfileOperation) Done() bool { - return op.lro.Done() + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/connectionProfiles", req.GetParent()) + + params := url.Values{} + params.Add("connectionProfileId", fmt.Sprintf("%v", req.GetConnectionProfileId())) + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1alpha1/%s", resp.GetName()) + return &CreateConnectionProfileOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UpdateConnectionProfile use this method to update the parameters of a connection profile. +func (c *restClient) UpdateConnectionProfile(ctx context.Context, req *datastreampb.UpdateConnectionProfileRequest, opts ...gax.CallOption) (*UpdateConnectionProfileOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetConnectionProfile() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetConnectionProfile().GetName()) + + params := url.Values{} + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "connection_profile.name", url.QueryEscape(req.GetConnectionProfile().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1alpha1/%s", resp.GetName()) + return &UpdateConnectionProfileOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// DeleteConnectionProfile use this method to delete a connection profile… +func (c *restClient) DeleteConnectionProfile(ctx context.Context, req *datastreampb.DeleteConnectionProfileRequest, opts ...gax.CallOption) (*DeleteConnectionProfileOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetName()) + + params := url.Values{} + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1alpha1/%s", resp.GetName()) + return &DeleteConnectionProfileOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// DiscoverConnectionProfile use this method to discover a connection profile. +// The discover API call exposes the data objects and metadata belonging to +// the profile. Typically, a request returns children data objects under a +// parent data object that’s optionally supplied in the request. +func (c *restClient) DiscoverConnectionProfile(ctx context.Context, req *datastreampb.DiscoverConnectionProfileRequest, opts ...gax.CallOption) (*datastreampb.DiscoverConnectionProfileResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/connectionProfiles:discover", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).DiscoverConnectionProfile[0:len((*c.CallOptions).DiscoverConnectionProfile):len((*c.CallOptions).DiscoverConnectionProfile)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &datastreampb.DiscoverConnectionProfileResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListStreams use this method to list streams in a project and location. +func (c *restClient) ListStreams(ctx context.Context, req *datastreampb.ListStreamsRequest, opts ...gax.CallOption) *StreamIterator { + it := &StreamIterator{} + req = proto.Clone(req).(*datastreampb.ListStreamsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*datastreampb.Stream, string, error) { + resp := &datastreampb.ListStreamsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/streams", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetOrderBy() != "" { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetStreams(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetStream use this method to get details about a stream. +func (c *restClient) GetStream(ctx context.Context, req *datastreampb.GetStreamRequest, opts ...gax.CallOption) (*datastreampb.Stream, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetStream[0:len((*c.CallOptions).GetStream):len((*c.CallOptions).GetStream)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &datastreampb.Stream{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateStream use this method to create a stream. +func (c *restClient) CreateStream(ctx context.Context, req *datastreampb.CreateStreamRequest, opts ...gax.CallOption) (*CreateStreamOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetStream() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/streams", req.GetParent()) + + params := url.Values{} + if req.GetForce() { + params.Add("force", fmt.Sprintf("%v", req.GetForce())) + } + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + params.Add("streamId", fmt.Sprintf("%v", req.GetStreamId())) + if req.GetValidateOnly() { + params.Add("validateOnly", fmt.Sprintf("%v", req.GetValidateOnly())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1alpha1/%s", resp.GetName()) + return &CreateStreamOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UpdateStream use this method to update the configuration of a stream. +func (c *restClient) UpdateStream(ctx context.Context, req *datastreampb.UpdateStreamRequest, opts ...gax.CallOption) (*UpdateStreamOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetStream() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetStream().GetName()) + + params := url.Values{} + if req.GetForce() { + params.Add("force", fmt.Sprintf("%v", req.GetForce())) + } + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + if req.GetValidateOnly() { + params.Add("validateOnly", fmt.Sprintf("%v", req.GetValidateOnly())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "stream.name", url.QueryEscape(req.GetStream().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1alpha1/%s", resp.GetName()) + return &UpdateStreamOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// DeleteStream use this method to delete a stream. +func (c *restClient) DeleteStream(ctx context.Context, req *datastreampb.DeleteStreamRequest, opts ...gax.CallOption) (*DeleteStreamOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetName()) + + params := url.Values{} + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1alpha1/%s", resp.GetName()) + return &DeleteStreamOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// FetchErrors use this method to fetch any errors associated with a stream. +func (c *restClient) FetchErrors(ctx context.Context, req *datastreampb.FetchErrorsRequest, opts ...gax.CallOption) (*FetchErrorsOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v:fetchErrors", req.GetStream()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "stream", url.QueryEscape(req.GetStream()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1alpha1/%s", resp.GetName()) + return &FetchErrorsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// FetchStaticIps the FetchStaticIps API call exposes the static ips used by Datastream. +// Typically, a request returns children data objects under +// a parent data object that’s optionally supplied in the request. +func (c *restClient) FetchStaticIps(ctx context.Context, req *datastreampb.FetchStaticIpsRequest, opts ...gax.CallOption) *StringIterator { + it := &StringIterator{} + req = proto.Clone(req).(*datastreampb.FetchStaticIpsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]string, string, error) { + resp := &datastreampb.FetchStaticIpsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v:fetchStaticIps", req.GetName()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetStaticIps(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CreatePrivateConnection use this method to create a private connectivity configuration. +func (c *restClient) CreatePrivateConnection(ctx context.Context, req *datastreampb.CreatePrivateConnectionRequest, opts ...gax.CallOption) (*CreatePrivateConnectionOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetPrivateConnection() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/privateConnections", req.GetParent()) + + params := url.Values{} + params.Add("privateConnectionId", fmt.Sprintf("%v", req.GetPrivateConnectionId())) + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1alpha1/%s", resp.GetName()) + return &CreatePrivateConnectionOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// GetPrivateConnection use this method to get details about a private connectivity configuration. +func (c *restClient) GetPrivateConnection(ctx context.Context, req *datastreampb.GetPrivateConnectionRequest, opts ...gax.CallOption) (*datastreampb.PrivateConnection, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetPrivateConnection[0:len((*c.CallOptions).GetPrivateConnection):len((*c.CallOptions).GetPrivateConnection)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &datastreampb.PrivateConnection{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListPrivateConnections use this method to list private connectivity configurations in a project +// and location. +func (c *restClient) ListPrivateConnections(ctx context.Context, req *datastreampb.ListPrivateConnectionsRequest, opts ...gax.CallOption) *PrivateConnectionIterator { + it := &PrivateConnectionIterator{} + req = proto.Clone(req).(*datastreampb.ListPrivateConnectionsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*datastreampb.PrivateConnection, string, error) { + resp := &datastreampb.ListPrivateConnectionsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/privateConnections", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetOrderBy() != "" { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetPrivateConnections(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// DeletePrivateConnection use this method to delete a private connectivity configuration. +func (c *restClient) DeletePrivateConnection(ctx context.Context, req *datastreampb.DeletePrivateConnectionRequest, opts ...gax.CallOption) (*DeletePrivateConnectionOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetName()) + + params := url.Values{} + if req.GetForce() { + params.Add("force", fmt.Sprintf("%v", req.GetForce())) + } + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1alpha1/%s", resp.GetName()) + return &DeletePrivateConnectionOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// CreateRoute use this method to create a route for a private connectivity in a project +// and location. +func (c *restClient) CreateRoute(ctx context.Context, req *datastreampb.CreateRouteRequest, opts ...gax.CallOption) (*CreateRouteOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetRoute() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/routes", req.GetParent()) + + params := url.Values{} + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + params.Add("routeId", fmt.Sprintf("%v", req.GetRouteId())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1alpha1/%s", resp.GetName()) + return &CreateRouteOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// GetRoute use this method to get details about a route. +func (c *restClient) GetRoute(ctx context.Context, req *datastreampb.GetRouteRequest, opts ...gax.CallOption) (*datastreampb.Route, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetRoute[0:len((*c.CallOptions).GetRoute):len((*c.CallOptions).GetRoute)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &datastreampb.Route{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListRoutes use this method to list routes created for a private connectivity in a +// project and location. +func (c *restClient) ListRoutes(ctx context.Context, req *datastreampb.ListRoutesRequest, opts ...gax.CallOption) *RouteIterator { + it := &RouteIterator{} + req = proto.Clone(req).(*datastreampb.ListRoutesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*datastreampb.Route, string, error) { + resp := &datastreampb.ListRoutesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v/routes", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetOrderBy() != "" { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetRoutes(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// DeleteRoute use this method to delete a route. +func (c *restClient) DeleteRoute(ctx context.Context, req *datastreampb.DeleteRouteRequest, opts ...gax.CallOption) (*DeleteRouteOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha1/%v", req.GetName()) + + params := url.Values{} + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1alpha1/%s", resp.GetName()) + return &DeleteRouteOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// CreateConnectionProfileOperation manages a long-running operation from CreateConnectionProfile. +type CreateConnectionProfileOperation struct { + lro *longrunning.Operation + pollPath string +} + +// CreateConnectionProfileOperation returns a new CreateConnectionProfileOperation from a given name. +// The name must be that of a previously created CreateConnectionProfileOperation, possibly from a different process. +func (c *gRPCClient) CreateConnectionProfileOperation(name string) *CreateConnectionProfileOperation { + return &CreateConnectionProfileOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// CreateConnectionProfileOperation returns a new CreateConnectionProfileOperation from a given name. +// The name must be that of a previously created CreateConnectionProfileOperation, possibly from a different process. +func (c *restClient) CreateConnectionProfileOperation(name string) *CreateConnectionProfileOperation { + override := fmt.Sprintf("/v1alpha1/%s", name) + return &CreateConnectionProfileOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateConnectionProfileOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*datastreampb.ConnectionProfile, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp datastreampb.ConnectionProfile + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateConnectionProfileOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*datastreampb.ConnectionProfile, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp datastreampb.ConnectionProfile + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateConnectionProfileOperation) Metadata() (*datastreampb.OperationMetadata, error) { + var meta datastreampb.OperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateConnectionProfileOperation) Done() bool { + return op.lro.Done() } // Name returns the name of the long-running operation. @@ -1237,7 +2973,8 @@ func (op *CreateConnectionProfileOperation) Name() string { // CreatePrivateConnectionOperation manages a long-running operation from CreatePrivateConnection. type CreatePrivateConnectionOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // CreatePrivateConnectionOperation returns a new CreatePrivateConnectionOperation from a given name. @@ -1248,10 +2985,21 @@ func (c *gRPCClient) CreatePrivateConnectionOperation(name string) *CreatePrivat } } +// CreatePrivateConnectionOperation returns a new CreatePrivateConnectionOperation from a given name. +// The name must be that of a previously created CreatePrivateConnectionOperation, possibly from a different process. +func (c *restClient) CreatePrivateConnectionOperation(name string) *CreatePrivateConnectionOperation { + override := fmt.Sprintf("/v1alpha1/%s", name) + return &CreatePrivateConnectionOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *CreatePrivateConnectionOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*datastreampb.PrivateConnection, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp datastreampb.PrivateConnection if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1269,6 +3017,7 @@ func (op *CreatePrivateConnectionOperation) Wait(ctx context.Context, opts ...ga // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *CreatePrivateConnectionOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*datastreampb.PrivateConnection, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp datastreampb.PrivateConnection if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1306,7 +3055,8 @@ func (op *CreatePrivateConnectionOperation) Name() string { // CreateRouteOperation manages a long-running operation from CreateRoute. type CreateRouteOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // CreateRouteOperation returns a new CreateRouteOperation from a given name. @@ -1317,10 +3067,21 @@ func (c *gRPCClient) CreateRouteOperation(name string) *CreateRouteOperation { } } +// CreateRouteOperation returns a new CreateRouteOperation from a given name. +// The name must be that of a previously created CreateRouteOperation, possibly from a different process. +func (c *restClient) CreateRouteOperation(name string) *CreateRouteOperation { + override := fmt.Sprintf("/v1alpha1/%s", name) + return &CreateRouteOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *CreateRouteOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*datastreampb.Route, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp datastreampb.Route if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1338,6 +3099,7 @@ func (op *CreateRouteOperation) Wait(ctx context.Context, opts ...gax.CallOption // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *CreateRouteOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*datastreampb.Route, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp datastreampb.Route if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1375,7 +3137,8 @@ func (op *CreateRouteOperation) Name() string { // CreateStreamOperation manages a long-running operation from CreateStream. type CreateStreamOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // CreateStreamOperation returns a new CreateStreamOperation from a given name. @@ -1386,10 +3149,21 @@ func (c *gRPCClient) CreateStreamOperation(name string) *CreateStreamOperation { } } +// CreateStreamOperation returns a new CreateStreamOperation from a given name. +// The name must be that of a previously created CreateStreamOperation, possibly from a different process. +func (c *restClient) CreateStreamOperation(name string) *CreateStreamOperation { + override := fmt.Sprintf("/v1alpha1/%s", name) + return &CreateStreamOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *CreateStreamOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*datastreampb.Stream, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp datastreampb.Stream if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1407,6 +3181,7 @@ func (op *CreateStreamOperation) Wait(ctx context.Context, opts ...gax.CallOptio // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *CreateStreamOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*datastreampb.Stream, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp datastreampb.Stream if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1444,7 +3219,8 @@ func (op *CreateStreamOperation) Name() string { // DeleteConnectionProfileOperation manages a long-running operation from DeleteConnectionProfile. type DeleteConnectionProfileOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // DeleteConnectionProfileOperation returns a new DeleteConnectionProfileOperation from a given name. @@ -1455,10 +3231,21 @@ func (c *gRPCClient) DeleteConnectionProfileOperation(name string) *DeleteConnec } } +// DeleteConnectionProfileOperation returns a new DeleteConnectionProfileOperation from a given name. +// The name must be that of a previously created DeleteConnectionProfileOperation, possibly from a different process. +func (c *restClient) DeleteConnectionProfileOperation(name string) *DeleteConnectionProfileOperation { + override := fmt.Sprintf("/v1alpha1/%s", name) + return &DeleteConnectionProfileOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *DeleteConnectionProfileOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1472,6 +3259,7 @@ func (op *DeleteConnectionProfileOperation) Wait(ctx context.Context, opts ...ga // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeleteConnectionProfileOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1502,7 +3290,8 @@ func (op *DeleteConnectionProfileOperation) Name() string { // DeletePrivateConnectionOperation manages a long-running operation from DeletePrivateConnection. type DeletePrivateConnectionOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // DeletePrivateConnectionOperation returns a new DeletePrivateConnectionOperation from a given name. @@ -1513,10 +3302,21 @@ func (c *gRPCClient) DeletePrivateConnectionOperation(name string) *DeletePrivat } } +// DeletePrivateConnectionOperation returns a new DeletePrivateConnectionOperation from a given name. +// The name must be that of a previously created DeletePrivateConnectionOperation, possibly from a different process. +func (c *restClient) DeletePrivateConnectionOperation(name string) *DeletePrivateConnectionOperation { + override := fmt.Sprintf("/v1alpha1/%s", name) + return &DeletePrivateConnectionOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *DeletePrivateConnectionOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1530,6 +3330,7 @@ func (op *DeletePrivateConnectionOperation) Wait(ctx context.Context, opts ...ga // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeletePrivateConnectionOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1560,7 +3361,8 @@ func (op *DeletePrivateConnectionOperation) Name() string { // DeleteRouteOperation manages a long-running operation from DeleteRoute. type DeleteRouteOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // DeleteRouteOperation returns a new DeleteRouteOperation from a given name. @@ -1571,10 +3373,21 @@ func (c *gRPCClient) DeleteRouteOperation(name string) *DeleteRouteOperation { } } +// DeleteRouteOperation returns a new DeleteRouteOperation from a given name. +// The name must be that of a previously created DeleteRouteOperation, possibly from a different process. +func (c *restClient) DeleteRouteOperation(name string) *DeleteRouteOperation { + override := fmt.Sprintf("/v1alpha1/%s", name) + return &DeleteRouteOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *DeleteRouteOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1588,6 +3401,7 @@ func (op *DeleteRouteOperation) Wait(ctx context.Context, opts ...gax.CallOption // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeleteRouteOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1618,7 +3432,8 @@ func (op *DeleteRouteOperation) Name() string { // DeleteStreamOperation manages a long-running operation from DeleteStream. type DeleteStreamOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // DeleteStreamOperation returns a new DeleteStreamOperation from a given name. @@ -1629,10 +3444,21 @@ func (c *gRPCClient) DeleteStreamOperation(name string) *DeleteStreamOperation { } } +// DeleteStreamOperation returns a new DeleteStreamOperation from a given name. +// The name must be that of a previously created DeleteStreamOperation, possibly from a different process. +func (c *restClient) DeleteStreamOperation(name string) *DeleteStreamOperation { + override := fmt.Sprintf("/v1alpha1/%s", name) + return &DeleteStreamOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *DeleteStreamOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1646,6 +3472,7 @@ func (op *DeleteStreamOperation) Wait(ctx context.Context, opts ...gax.CallOptio // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeleteStreamOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1676,7 +3503,8 @@ func (op *DeleteStreamOperation) Name() string { // FetchErrorsOperation manages a long-running operation from FetchErrors. type FetchErrorsOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // FetchErrorsOperation returns a new FetchErrorsOperation from a given name. @@ -1687,10 +3515,21 @@ func (c *gRPCClient) FetchErrorsOperation(name string) *FetchErrorsOperation { } } +// FetchErrorsOperation returns a new FetchErrorsOperation from a given name. +// The name must be that of a previously created FetchErrorsOperation, possibly from a different process. +func (c *restClient) FetchErrorsOperation(name string) *FetchErrorsOperation { + override := fmt.Sprintf("/v1alpha1/%s", name) + return &FetchErrorsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *FetchErrorsOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*datastreampb.FetchErrorsResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp datastreampb.FetchErrorsResponse if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1708,6 +3547,7 @@ func (op *FetchErrorsOperation) Wait(ctx context.Context, opts ...gax.CallOption // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *FetchErrorsOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*datastreampb.FetchErrorsResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp datastreampb.FetchErrorsResponse if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1745,7 +3585,8 @@ func (op *FetchErrorsOperation) Name() string { // UpdateConnectionProfileOperation manages a long-running operation from UpdateConnectionProfile. type UpdateConnectionProfileOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UpdateConnectionProfileOperation returns a new UpdateConnectionProfileOperation from a given name. @@ -1756,10 +3597,21 @@ func (c *gRPCClient) UpdateConnectionProfileOperation(name string) *UpdateConnec } } +// UpdateConnectionProfileOperation returns a new UpdateConnectionProfileOperation from a given name. +// The name must be that of a previously created UpdateConnectionProfileOperation, possibly from a different process. +func (c *restClient) UpdateConnectionProfileOperation(name string) *UpdateConnectionProfileOperation { + override := fmt.Sprintf("/v1alpha1/%s", name) + return &UpdateConnectionProfileOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UpdateConnectionProfileOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*datastreampb.ConnectionProfile, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp datastreampb.ConnectionProfile if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1777,6 +3629,7 @@ func (op *UpdateConnectionProfileOperation) Wait(ctx context.Context, opts ...ga // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UpdateConnectionProfileOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*datastreampb.ConnectionProfile, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp datastreampb.ConnectionProfile if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1814,7 +3667,8 @@ func (op *UpdateConnectionProfileOperation) Name() string { // UpdateStreamOperation manages a long-running operation from UpdateStream. type UpdateStreamOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UpdateStreamOperation returns a new UpdateStreamOperation from a given name. @@ -1825,10 +3679,21 @@ func (c *gRPCClient) UpdateStreamOperation(name string) *UpdateStreamOperation { } } +// UpdateStreamOperation returns a new UpdateStreamOperation from a given name. +// The name must be that of a previously created UpdateStreamOperation, possibly from a different process. +func (c *restClient) UpdateStreamOperation(name string) *UpdateStreamOperation { + override := fmt.Sprintf("/v1alpha1/%s", name) + return &UpdateStreamOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UpdateStreamOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*datastreampb.Stream, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp datastreampb.Stream if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1846,6 +3711,7 @@ func (op *UpdateStreamOperation) Wait(ctx context.Context, opts ...gax.CallOptio // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UpdateStreamOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*datastreampb.Stream, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp datastreampb.Stream if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/datastream/apiv1alpha1/datastream_client_example_test.go b/datastream/apiv1alpha1/datastream_client_example_test.go index cadb2f0ad433..585afb7f2d7d 100644 --- a/datastream/apiv1alpha1/datastream_client_example_test.go +++ b/datastream/apiv1alpha1/datastream_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := datastream.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_ListConnectionProfiles() { ctx := context.Background() c, err := datastream.NewClient(ctx) diff --git a/datastream/apiv1alpha1/doc.go b/datastream/apiv1alpha1/doc.go index 67061c9d2d21..374a068a1eef 100644 --- a/datastream/apiv1alpha1/doc.go +++ b/datastream/apiv1alpha1/doc.go @@ -75,6 +75,8 @@ package datastream // import "cloud.google.com/go/datastream/apiv1alpha1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -163,3 +165,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/datastream/apiv1alpha1/gapic_metadata.json b/datastream/apiv1alpha1/gapic_metadata.json index 417ecf9c4390..a5f19771c16e 100644 --- a/datastream/apiv1alpha1/gapic_metadata.json +++ b/datastream/apiv1alpha1/gapic_metadata.json @@ -116,6 +116,116 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "CreateConnectionProfile": { + "methods": [ + "CreateConnectionProfile" + ] + }, + "CreatePrivateConnection": { + "methods": [ + "CreatePrivateConnection" + ] + }, + "CreateRoute": { + "methods": [ + "CreateRoute" + ] + }, + "CreateStream": { + "methods": [ + "CreateStream" + ] + }, + "DeleteConnectionProfile": { + "methods": [ + "DeleteConnectionProfile" + ] + }, + "DeletePrivateConnection": { + "methods": [ + "DeletePrivateConnection" + ] + }, + "DeleteRoute": { + "methods": [ + "DeleteRoute" + ] + }, + "DeleteStream": { + "methods": [ + "DeleteStream" + ] + }, + "DiscoverConnectionProfile": { + "methods": [ + "DiscoverConnectionProfile" + ] + }, + "FetchErrors": { + "methods": [ + "FetchErrors" + ] + }, + "FetchStaticIps": { + "methods": [ + "FetchStaticIps" + ] + }, + "GetConnectionProfile": { + "methods": [ + "GetConnectionProfile" + ] + }, + "GetPrivateConnection": { + "methods": [ + "GetPrivateConnection" + ] + }, + "GetRoute": { + "methods": [ + "GetRoute" + ] + }, + "GetStream": { + "methods": [ + "GetStream" + ] + }, + "ListConnectionProfiles": { + "methods": [ + "ListConnectionProfiles" + ] + }, + "ListPrivateConnections": { + "methods": [ + "ListPrivateConnections" + ] + }, + "ListRoutes": { + "methods": [ + "ListRoutes" + ] + }, + "ListStreams": { + "methods": [ + "ListStreams" + ] + }, + "UpdateConnectionProfile": { + "methods": [ + "UpdateConnectionProfile" + ] + }, + "UpdateStream": { + "methods": [ + "UpdateStream" + ] + } + } } } } diff --git a/dialogflow/cx/apiv3beta1/agents_client.go b/dialogflow/cx/apiv3beta1/agents_client.go index 6d64d535efe8..aacd2a56d24d 100644 --- a/dialogflow/cx/apiv3beta1/agents_client.go +++ b/dialogflow/cx/apiv3beta1/agents_client.go @@ -17,9 +17,12 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" @@ -27,16 +30,19 @@ import ( lroauto "cloud.google.com/go/longrunning/autogen" structpb "github.com/golang/protobuf/ptypes/struct" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -181,6 +187,106 @@ func defaultAgentsCallOptions() *AgentsCallOptions { } } +func defaultAgentsRESTCallOptions() *AgentsCallOptions { + return &AgentsCallOptions{ + ListAgents: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetAgent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateAgent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateAgent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteAgent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ExportAgent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + RestoreAgent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ValidateAgent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetAgentValidationResult: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalAgentsClient is an interface that defines the methods available from Dialogflow API. type internalAgentsClient interface { Close() error @@ -464,6 +570,89 @@ func (c *agentsGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type agentsRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing AgentsClient + CallOptions **AgentsCallOptions +} + +// NewAgentsRESTClient creates a new agents rest client. +// +// Service for managing Agents. +func NewAgentsRESTClient(ctx context.Context, opts ...option.ClientOption) (*AgentsClient, error) { + clientOpts := append(defaultAgentsRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultAgentsRESTCallOptions() + c := &agentsRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &AgentsClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultAgentsRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *agentsRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *agentsRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *agentsRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *agentsGRPCClient) ListAgents(ctx context.Context, req *cxpb.ListAgentsRequest, opts ...gax.CallOption) *AgentIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -822,79 +1011,998 @@ func (c *agentsGRPCClient) ListOperations(ctx context.Context, req *longrunningp return it } -// ExportAgentOperation manages a long-running operation from ExportAgent. -type ExportAgentOperation struct { - lro *longrunning.Operation -} +// ListAgents returns the list of all agents in the specified location. +func (c *agentsRESTClient) ListAgents(ctx context.Context, req *cxpb.ListAgentsRequest, opts ...gax.CallOption) *AgentIterator { + it := &AgentIterator{} + req = proto.Clone(req).(*cxpb.ListAgentsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.Agent, string, error) { + resp := &cxpb.ListAgentsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/agents", req.GetParent()) -// ExportAgentOperation returns a new ExportAgentOperation from a given name. -// The name must be that of a previously created ExportAgentOperation, possibly from a different process. -func (c *agentsGRPCClient) ExportAgentOperation(name string) *ExportAgentOperation { - return &ExportAgentOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetAgents(), resp.GetNextPageToken(), nil } -} -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. -// -// See documentation of Poll for error-handling information. -func (op *ExportAgentOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.ExportAgentResponse, error) { - var resp cxpb.ExportAgentResponse - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - return &resp, nil + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it } -// Poll fetches the latest state of the long-running operation. -// -// Poll also fetches the latest metadata, which can be retrieved by Metadata. -// -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *ExportAgentOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.ExportAgentResponse, error) { - var resp cxpb.ExportAgentResponse - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { +// GetAgent retrieves the specified agent. +func (c *agentsRESTClient) GetAgent(ctx context.Context, req *cxpb.GetAgentRequest, opts ...gax.CallOption) (*cxpb.Agent, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - if !op.Done() { - return nil, nil + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetAgent[0:len((*c.CallOptions).GetAgent):len((*c.CallOptions).GetAgent)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Agent{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e } - return &resp, nil + return resp, nil } -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. -// If the metadata is not available, the returned metadata and error are both nil. -func (op *ExportAgentOperation) Metadata() (*structpb.Struct, error) { - var meta structpb.Struct - if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { - return nil, nil - } else if err != nil { +// CreateAgent creates an agent in the specified location. +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *agentsRESTClient) CreateAgent(ctx context.Context, req *cxpb.CreateAgentRequest, opts ...gax.CallOption) (*cxpb.Agent, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetAgent() + jsonReq, err := m.Marshal(body) + if err != nil { return nil, err } - return &meta, nil -} -// Done reports whether the long-running operation has completed. -func (op *ExportAgentOperation) Done() bool { - return op.lro.Done() -} + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/agents", req.GetParent()) -// Name returns the name of the long-running operation. -// The name is assigned by the server and is unique within the service from which the operation is created. -func (op *ExportAgentOperation) Name() string { - return op.lro.Name() -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) -// RestoreAgentOperation manages a long-running operation from RestoreAgent. -type RestoreAgentOperation struct { - lro *longrunning.Operation -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateAgent[0:len((*c.CallOptions).CreateAgent):len((*c.CallOptions).CreateAgent)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Agent{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateAgent updates the specified agent. +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *agentsRESTClient) UpdateAgent(ctx context.Context, req *cxpb.UpdateAgentRequest, opts ...gax.CallOption) (*cxpb.Agent, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetAgent() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetAgent().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "agent.name", url.QueryEscape(req.GetAgent().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateAgent[0:len((*c.CallOptions).UpdateAgent):len((*c.CallOptions).UpdateAgent)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Agent{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteAgent deletes the specified agent. +func (c *agentsRESTClient) DeleteAgent(ctx context.Context, req *cxpb.DeleteAgentRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// ExportAgent exports the specified agent to a binary file. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: An empty Struct +// message (at https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#struct) +// +// response: ExportAgentResponse +func (c *agentsRESTClient) ExportAgent(ctx context.Context, req *cxpb.ExportAgentRequest, opts ...gax.CallOption) (*ExportAgentOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:export", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &ExportAgentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// RestoreAgent restores the specified agent from a binary file. +// +// Replaces the current agent with a new one. Note that all existing resources +// in agent (e.g. intents, entity types, flows) will be removed. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: An empty Struct +// message (at https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#struct) +// +// response: An Empty +// message (at https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#empty) +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *agentsRESTClient) RestoreAgent(ctx context.Context, req *cxpb.RestoreAgentRequest, opts ...gax.CallOption) (*RestoreAgentOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:restore", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &RestoreAgentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ValidateAgent validates the specified agent and creates or updates validation results. +// The agent in draft version is validated. Please call this API after the +// training is completed to get the complete validation results. +func (c *agentsRESTClient) ValidateAgent(ctx context.Context, req *cxpb.ValidateAgentRequest, opts ...gax.CallOption) (*cxpb.AgentValidationResult, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:validate", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ValidateAgent[0:len((*c.CallOptions).ValidateAgent):len((*c.CallOptions).ValidateAgent)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.AgentValidationResult{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetAgentValidationResult gets the latest agent validation result. Agent validation is performed +// when ValidateAgent is called. +func (c *agentsRESTClient) GetAgentValidationResult(ctx context.Context, req *cxpb.GetAgentValidationResultRequest, opts ...gax.CallOption) (*cxpb.AgentValidationResult, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetAgentValidationResult[0:len((*c.CallOptions).GetAgentValidationResult):len((*c.CallOptions).GetAgentValidationResult)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.AgentValidationResult{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetLocation gets information about a location. +func (c *agentsRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *agentsRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *agentsRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *agentsRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *agentsRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// ExportAgentOperation manages a long-running operation from ExportAgent. +type ExportAgentOperation struct { + lro *longrunning.Operation + pollPath string +} + +// ExportAgentOperation returns a new ExportAgentOperation from a given name. +// The name must be that of a previously created ExportAgentOperation, possibly from a different process. +func (c *agentsGRPCClient) ExportAgentOperation(name string) *ExportAgentOperation { + return &ExportAgentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// ExportAgentOperation returns a new ExportAgentOperation from a given name. +// The name must be that of a previously created ExportAgentOperation, possibly from a different process. +func (c *agentsRESTClient) ExportAgentOperation(name string) *ExportAgentOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &ExportAgentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *ExportAgentOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.ExportAgentResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp cxpb.ExportAgentResponse + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *ExportAgentOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.ExportAgentResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp cxpb.ExportAgentResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *ExportAgentOperation) Metadata() (*structpb.Struct, error) { + var meta structpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *ExportAgentOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *ExportAgentOperation) Name() string { + return op.lro.Name() +} + +// RestoreAgentOperation manages a long-running operation from RestoreAgent. +type RestoreAgentOperation struct { + lro *longrunning.Operation + pollPath string +} // RestoreAgentOperation returns a new RestoreAgentOperation from a given name. // The name must be that of a previously created RestoreAgentOperation, possibly from a different process. @@ -904,10 +2012,21 @@ func (c *agentsGRPCClient) RestoreAgentOperation(name string) *RestoreAgentOpera } } +// RestoreAgentOperation returns a new RestoreAgentOperation from a given name. +// The name must be that of a previously created RestoreAgentOperation, possibly from a different process. +func (c *agentsRESTClient) RestoreAgentOperation(name string) *RestoreAgentOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &RestoreAgentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *RestoreAgentOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -921,6 +2040,7 @@ func (op *RestoreAgentOperation) Wait(ctx context.Context, opts ...gax.CallOptio // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *RestoreAgentOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } diff --git a/dialogflow/cx/apiv3beta1/agents_client_example_test.go b/dialogflow/cx/apiv3beta1/agents_client_example_test.go index a84cfe03f2de..aa910a6f3c61 100644 --- a/dialogflow/cx/apiv3beta1/agents_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/agents_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewAgentsClient() { _ = c } +func ExampleNewAgentsRESTClient() { + ctx := context.Background() + c, err := cx.NewAgentsRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleAgentsClient_ListAgents() { ctx := context.Background() c, err := cx.NewAgentsClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/changelogs_client.go b/dialogflow/cx/apiv3beta1/changelogs_client.go index ded54cb22f3d..4aff825e6af2 100644 --- a/dialogflow/cx/apiv3beta1/changelogs_client.go +++ b/dialogflow/cx/apiv3beta1/changelogs_client.go @@ -19,21 +19,26 @@ package cx import ( "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -94,6 +99,36 @@ func defaultChangelogsCallOptions() *ChangelogsCallOptions { } } +func defaultChangelogsRESTCallOptions() *ChangelogsCallOptions { + return &ChangelogsCallOptions{ + ListChangelogs: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetChangelog: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalChangelogsClient is an interface that defines the methods available from Dialogflow API. type internalChangelogsClient interface { Close() error @@ -263,6 +298,74 @@ func (c *changelogsGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type changelogsRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing ChangelogsClient + CallOptions **ChangelogsCallOptions +} + +// NewChangelogsRESTClient creates a new changelogs rest client. +// +// Service for managing Changelogs. +func NewChangelogsRESTClient(ctx context.Context, opts ...option.ClientOption) (*ChangelogsClient, error) { + clientOpts := append(defaultChangelogsRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultChangelogsRESTCallOptions() + c := &changelogsRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &ChangelogsClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultChangelogsRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *changelogsRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *changelogsRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *changelogsRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *changelogsGRPCClient) ListChangelogs(ctx context.Context, req *cxpb.ListChangelogsRequest, opts ...gax.CallOption) *ChangelogIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -467,6 +570,470 @@ func (c *changelogsGRPCClient) ListOperations(ctx context.Context, req *longrunn return it } +// ListChangelogs returns the list of Changelogs. +func (c *changelogsRESTClient) ListChangelogs(ctx context.Context, req *cxpb.ListChangelogsRequest, opts ...gax.CallOption) *ChangelogIterator { + it := &ChangelogIterator{} + req = proto.Clone(req).(*cxpb.ListChangelogsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.Changelog, string, error) { + resp := &cxpb.ListChangelogsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/changelogs", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetChangelogs(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetChangelog retrieves the specified Changelog. +func (c *changelogsRESTClient) GetChangelog(ctx context.Context, req *cxpb.GetChangelogRequest, opts ...gax.CallOption) (*cxpb.Changelog, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetChangelog[0:len((*c.CallOptions).GetChangelog):len((*c.CallOptions).GetChangelog)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Changelog{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetLocation gets information about a location. +func (c *changelogsRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *changelogsRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *changelogsRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *changelogsRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *changelogsRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // ChangelogIterator manages a stream of *cxpb.Changelog. type ChangelogIterator struct { items []*cxpb.Changelog diff --git a/dialogflow/cx/apiv3beta1/changelogs_client_example_test.go b/dialogflow/cx/apiv3beta1/changelogs_client_example_test.go index c96b639af4df..e04eb4790908 100644 --- a/dialogflow/cx/apiv3beta1/changelogs_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/changelogs_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewChangelogsClient() { _ = c } +func ExampleNewChangelogsRESTClient() { + ctx := context.Background() + c, err := cx.NewChangelogsRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleChangelogsClient_ListChangelogs() { ctx := context.Background() c, err := cx.NewChangelogsClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/deployments_client.go b/dialogflow/cx/apiv3beta1/deployments_client.go index d71d9542dcf1..3459ce49ea7b 100644 --- a/dialogflow/cx/apiv3beta1/deployments_client.go +++ b/dialogflow/cx/apiv3beta1/deployments_client.go @@ -19,21 +19,26 @@ package cx import ( "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -94,6 +99,36 @@ func defaultDeploymentsCallOptions() *DeploymentsCallOptions { } } +func defaultDeploymentsRESTCallOptions() *DeploymentsCallOptions { + return &DeploymentsCallOptions{ + ListDeployments: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetDeployment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalDeploymentsClient is an interface that defines the methods available from Dialogflow API. type internalDeploymentsClient interface { Close() error @@ -263,6 +298,74 @@ func (c *deploymentsGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type deploymentsRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing DeploymentsClient + CallOptions **DeploymentsCallOptions +} + +// NewDeploymentsRESTClient creates a new deployments rest client. +// +// Service for managing Deployments. +func NewDeploymentsRESTClient(ctx context.Context, opts ...option.ClientOption) (*DeploymentsClient, error) { + clientOpts := append(defaultDeploymentsRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultDeploymentsRESTCallOptions() + c := &deploymentsRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &DeploymentsClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultDeploymentsRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *deploymentsRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *deploymentsRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *deploymentsRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *deploymentsGRPCClient) ListDeployments(ctx context.Context, req *cxpb.ListDeploymentsRequest, opts ...gax.CallOption) *DeploymentIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -467,6 +570,467 @@ func (c *deploymentsGRPCClient) ListOperations(ctx context.Context, req *longrun return it } +// ListDeployments returns the list of all deployments in the specified Environment. +func (c *deploymentsRESTClient) ListDeployments(ctx context.Context, req *cxpb.ListDeploymentsRequest, opts ...gax.CallOption) *DeploymentIterator { + it := &DeploymentIterator{} + req = proto.Clone(req).(*cxpb.ListDeploymentsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.Deployment, string, error) { + resp := &cxpb.ListDeploymentsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/deployments", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetDeployments(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetDeployment retrieves the specified Deployment. +func (c *deploymentsRESTClient) GetDeployment(ctx context.Context, req *cxpb.GetDeploymentRequest, opts ...gax.CallOption) (*cxpb.Deployment, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetDeployment[0:len((*c.CallOptions).GetDeployment):len((*c.CallOptions).GetDeployment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Deployment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetLocation gets information about a location. +func (c *deploymentsRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *deploymentsRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *deploymentsRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *deploymentsRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *deploymentsRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // DeploymentIterator manages a stream of *cxpb.Deployment. type DeploymentIterator struct { items []*cxpb.Deployment diff --git a/dialogflow/cx/apiv3beta1/deployments_client_example_test.go b/dialogflow/cx/apiv3beta1/deployments_client_example_test.go index fb806e28301c..4e0eac8580d1 100644 --- a/dialogflow/cx/apiv3beta1/deployments_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/deployments_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewDeploymentsClient() { _ = c } +func ExampleNewDeploymentsRESTClient() { + ctx := context.Background() + c, err := cx.NewDeploymentsRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleDeploymentsClient_ListDeployments() { ctx := context.Background() c, err := cx.NewDeploymentsClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/doc.go b/dialogflow/cx/apiv3beta1/doc.go index 9c6f6334bec3..65062f219ca5 100644 --- a/dialogflow/cx/apiv3beta1/doc.go +++ b/dialogflow/cx/apiv3beta1/doc.go @@ -78,6 +78,8 @@ package cx // import "cloud.google.com/go/dialogflow/cx/apiv3beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -167,3 +169,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/dialogflow/cx/apiv3beta1/entity_types_client.go b/dialogflow/cx/apiv3beta1/entity_types_client.go index 5fc7e7102ada..a549286026b8 100644 --- a/dialogflow/cx/apiv3beta1/entity_types_client.go +++ b/dialogflow/cx/apiv3beta1/entity_types_client.go @@ -17,23 +17,29 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -130,6 +136,66 @@ func defaultEntityTypesCallOptions() *EntityTypesCallOptions { } } +func defaultEntityTypesRESTCallOptions() *EntityTypesCallOptions { + return &EntityTypesCallOptions{ + ListEntityTypes: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetEntityType: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateEntityType: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateEntityType: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteEntityType: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalEntityTypesClient is an interface that defines the methods available from Dialogflow API. type internalEntityTypesClient interface { Close() error @@ -325,6 +391,74 @@ func (c *entityTypesGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type entityTypesRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing EntityTypesClient + CallOptions **EntityTypesCallOptions +} + +// NewEntityTypesRESTClient creates a new entity types rest client. +// +// Service for managing EntityTypes. +func NewEntityTypesRESTClient(ctx context.Context, opts ...option.ClientOption) (*EntityTypesClient, error) { + clientOpts := append(defaultEntityTypesRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultEntityTypesRESTCallOptions() + c := &entityTypesRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &EntityTypesClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultEntityTypesRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *entityTypesRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *entityTypesRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *entityTypesRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *entityTypesGRPCClient) ListEntityTypes(ctx context.Context, req *cxpb.ListEntityTypesRequest, opts ...gax.CallOption) *EntityTypeIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -591,6 +725,664 @@ func (c *entityTypesGRPCClient) ListOperations(ctx context.Context, req *longrun return it } +// ListEntityTypes returns the list of all entity types in the specified agent. +func (c *entityTypesRESTClient) ListEntityTypes(ctx context.Context, req *cxpb.ListEntityTypesRequest, opts ...gax.CallOption) *EntityTypeIterator { + it := &EntityTypeIterator{} + req = proto.Clone(req).(*cxpb.ListEntityTypesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.EntityType, string, error) { + resp := &cxpb.ListEntityTypesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/entityTypes", req.GetParent()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetEntityTypes(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetEntityType retrieves the specified entity type. +func (c *entityTypesRESTClient) GetEntityType(ctx context.Context, req *cxpb.GetEntityTypeRequest, opts ...gax.CallOption) (*cxpb.EntityType, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetEntityType[0:len((*c.CallOptions).GetEntityType):len((*c.CallOptions).GetEntityType)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.EntityType{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateEntityType creates an entity type in the specified agent. +func (c *entityTypesRESTClient) CreateEntityType(ctx context.Context, req *cxpb.CreateEntityTypeRequest, opts ...gax.CallOption) (*cxpb.EntityType, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetEntityType() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/entityTypes", req.GetParent()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateEntityType[0:len((*c.CallOptions).CreateEntityType):len((*c.CallOptions).CreateEntityType)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.EntityType{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateEntityType updates the specified entity type. +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *entityTypesRESTClient) UpdateEntityType(ctx context.Context, req *cxpb.UpdateEntityTypeRequest, opts ...gax.CallOption) (*cxpb.EntityType, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetEntityType() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetEntityType().GetName()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "entity_type.name", url.QueryEscape(req.GetEntityType().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateEntityType[0:len((*c.CallOptions).UpdateEntityType):len((*c.CallOptions).UpdateEntityType)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.EntityType{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteEntityType deletes the specified entity type. +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *entityTypesRESTClient) DeleteEntityType(ctx context.Context, req *cxpb.DeleteEntityTypeRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetForce() { + params.Add("force", fmt.Sprintf("%v", req.GetForce())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetLocation gets information about a location. +func (c *entityTypesRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *entityTypesRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *entityTypesRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *entityTypesRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *entityTypesRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // EntityTypeIterator manages a stream of *cxpb.EntityType. type EntityTypeIterator struct { items []*cxpb.EntityType diff --git a/dialogflow/cx/apiv3beta1/entity_types_client_example_test.go b/dialogflow/cx/apiv3beta1/entity_types_client_example_test.go index 13710c26e120..1bb084ccd987 100644 --- a/dialogflow/cx/apiv3beta1/entity_types_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/entity_types_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewEntityTypesClient() { _ = c } +func ExampleNewEntityTypesRESTClient() { + ctx := context.Background() + c, err := cx.NewEntityTypesRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleEntityTypesClient_ListEntityTypes() { ctx := context.Background() c, err := cx.NewEntityTypesClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/environments_client.go b/dialogflow/cx/apiv3beta1/environments_client.go index acbfe9064341..d9c14ece5b4e 100644 --- a/dialogflow/cx/apiv3beta1/environments_client.go +++ b/dialogflow/cx/apiv3beta1/environments_client.go @@ -17,9 +17,12 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" @@ -27,16 +30,19 @@ import ( lroauto "cloud.google.com/go/longrunning/autogen" structpb "github.com/golang/protobuf/ptypes/struct" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -181,6 +187,106 @@ func defaultEnvironmentsCallOptions() *EnvironmentsCallOptions { } } +func defaultEnvironmentsRESTCallOptions() *EnvironmentsCallOptions { + return &EnvironmentsCallOptions{ + ListEnvironments: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetEnvironment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateEnvironment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateEnvironment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteEnvironment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + LookupEnvironmentHistory: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + RunContinuousTest: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListContinuousTestResults: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeployFlow: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalEnvironmentsClient is an interface that defines the methods available from Dialogflow API. type internalEnvironmentsClient interface { Close() error @@ -475,6 +581,89 @@ func (c *environmentsGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type environmentsRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing EnvironmentsClient + CallOptions **EnvironmentsCallOptions +} + +// NewEnvironmentsRESTClient creates a new environments rest client. +// +// Service for managing Environments. +func NewEnvironmentsRESTClient(ctx context.Context, opts ...option.ClientOption) (*EnvironmentsClient, error) { + clientOpts := append(defaultEnvironmentsRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultEnvironmentsRESTCallOptions() + c := &environmentsRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &EnvironmentsClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultEnvironmentsRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *environmentsRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *environmentsRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *environmentsRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *environmentsGRPCClient) ListEnvironments(ctx context.Context, req *cxpb.ListEnvironmentsRequest, opts ...gax.CallOption) *EnvironmentIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -883,100 +1072,1090 @@ func (c *environmentsGRPCClient) ListOperations(ctx context.Context, req *longru return it } -// CreateEnvironmentOperation manages a long-running operation from CreateEnvironment. -type CreateEnvironmentOperation struct { - lro *longrunning.Operation -} +// ListEnvironments returns the list of all environments in the specified Agent. +func (c *environmentsRESTClient) ListEnvironments(ctx context.Context, req *cxpb.ListEnvironmentsRequest, opts ...gax.CallOption) *EnvironmentIterator { + it := &EnvironmentIterator{} + req = proto.Clone(req).(*cxpb.ListEnvironmentsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.Environment, string, error) { + resp := &cxpb.ListEnvironmentsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/environments", req.GetParent()) -// CreateEnvironmentOperation returns a new CreateEnvironmentOperation from a given name. -// The name must be that of a previously created CreateEnvironmentOperation, possibly from a different process. -func (c *environmentsGRPCClient) CreateEnvironmentOperation(name string) *CreateEnvironmentOperation { - return &CreateEnvironmentOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), - } -} + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. -// -// See documentation of Poll for error-handling information. -func (op *CreateEnvironmentOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.Environment, error) { - var resp cxpb.Environment - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { - return nil, err + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetEnvironments(), resp.GetNextPageToken(), nil } - return &resp, nil -} -// Poll fetches the latest state of the long-running operation. -// -// Poll also fetches the latest metadata, which can be retrieved by Metadata. -// -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *CreateEnvironmentOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.Environment, error) { - var resp cxpb.Environment - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { - return nil, err - } - if !op.Done() { - return nil, nil + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - return &resp, nil + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it } -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. -// If the metadata is not available, the returned metadata and error are both nil. -func (op *CreateEnvironmentOperation) Metadata() (*structpb.Struct, error) { - var meta structpb.Struct - if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { - return nil, nil - } else if err != nil { +// GetEnvironment retrieves the specified Environment. +func (c *environmentsRESTClient) GetEnvironment(ctx context.Context, req *cxpb.GetEnvironmentRequest, opts ...gax.CallOption) (*cxpb.Environment, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - return &meta, nil -} + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) -// Done reports whether the long-running operation has completed. -func (op *CreateEnvironmentOperation) Done() bool { - return op.lro.Done() -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) -// Name returns the name of the long-running operation. -// The name is assigned by the server and is unique within the service from which the operation is created. -func (op *CreateEnvironmentOperation) Name() string { - return op.lro.Name() -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetEnvironment[0:len((*c.CallOptions).GetEnvironment):len((*c.CallOptions).GetEnvironment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Environment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// DeployFlowOperation manages a long-running operation from DeployFlow. -type DeployFlowOperation struct { - lro *longrunning.Operation -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// DeployFlowOperation returns a new DeployFlowOperation from a given name. -// The name must be that of a previously created DeployFlowOperation, possibly from a different process. -func (c *environmentsGRPCClient) DeployFlowOperation(name string) *DeployFlowOperation { - return &DeployFlowOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), - } -} + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. -// -// See documentation of Poll for error-handling information. -func (op *DeployFlowOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.DeployFlowResponse, error) { - var resp cxpb.DeployFlowResponse - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { - return nil, err + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e } - return &resp, nil + return resp, nil } -// Poll fetches the latest state of the long-running operation. +// CreateEnvironment creates an Environment in the specified Agent. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: An empty Struct +// message (at https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#struct) +// +// response: Environment +func (c *environmentsRESTClient) CreateEnvironment(ctx context.Context, req *cxpb.CreateEnvironmentRequest, opts ...gax.CallOption) (*CreateEnvironmentOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetEnvironment() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/environments", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &CreateEnvironmentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UpdateEnvironment updates the specified Environment. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: An empty Struct +// message (at https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#struct) +// +// response: Environment +func (c *environmentsRESTClient) UpdateEnvironment(ctx context.Context, req *cxpb.UpdateEnvironmentRequest, opts ...gax.CallOption) (*UpdateEnvironmentOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetEnvironment() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetEnvironment().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "environment.name", url.QueryEscape(req.GetEnvironment().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &UpdateEnvironmentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// DeleteEnvironment deletes the specified Environment. +func (c *environmentsRESTClient) DeleteEnvironment(ctx context.Context, req *cxpb.DeleteEnvironmentRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// LookupEnvironmentHistory looks up the history of the specified Environment. +func (c *environmentsRESTClient) LookupEnvironmentHistory(ctx context.Context, req *cxpb.LookupEnvironmentHistoryRequest, opts ...gax.CallOption) *EnvironmentIterator { + it := &EnvironmentIterator{} + req = proto.Clone(req).(*cxpb.LookupEnvironmentHistoryRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.Environment, string, error) { + resp := &cxpb.LookupEnvironmentHistoryResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:lookupEnvironmentHistory", req.GetName()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetEnvironments(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// RunContinuousTest kicks off a continuous test under the specified Environment. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: RunContinuousTestMetadata +// +// response: RunContinuousTestResponse +func (c *environmentsRESTClient) RunContinuousTest(ctx context.Context, req *cxpb.RunContinuousTestRequest, opts ...gax.CallOption) (*RunContinuousTestOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:runContinuousTest", req.GetEnvironment()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "environment", url.QueryEscape(req.GetEnvironment()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &RunContinuousTestOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ListContinuousTestResults fetches a list of continuous test results for a given environment. +func (c *environmentsRESTClient) ListContinuousTestResults(ctx context.Context, req *cxpb.ListContinuousTestResultsRequest, opts ...gax.CallOption) *ContinuousTestResultIterator { + it := &ContinuousTestResultIterator{} + req = proto.Clone(req).(*cxpb.ListContinuousTestResultsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.ContinuousTestResult, string, error) { + resp := &cxpb.ListContinuousTestResultsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/continuousTestResults", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetContinuousTestResults(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// DeployFlow deploys a flow to the specified Environment. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: DeployFlowMetadata +// +// response: DeployFlowResponse +func (c *environmentsRESTClient) DeployFlow(ctx context.Context, req *cxpb.DeployFlowRequest, opts ...gax.CallOption) (*DeployFlowOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:deployFlow", req.GetEnvironment()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "environment", url.QueryEscape(req.GetEnvironment()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &DeployFlowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// GetLocation gets information about a location. +func (c *environmentsRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *environmentsRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *environmentsRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *environmentsRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *environmentsRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CreateEnvironmentOperation manages a long-running operation from CreateEnvironment. +type CreateEnvironmentOperation struct { + lro *longrunning.Operation + pollPath string +} + +// CreateEnvironmentOperation returns a new CreateEnvironmentOperation from a given name. +// The name must be that of a previously created CreateEnvironmentOperation, possibly from a different process. +func (c *environmentsGRPCClient) CreateEnvironmentOperation(name string) *CreateEnvironmentOperation { + return &CreateEnvironmentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// CreateEnvironmentOperation returns a new CreateEnvironmentOperation from a given name. +// The name must be that of a previously created CreateEnvironmentOperation, possibly from a different process. +func (c *environmentsRESTClient) CreateEnvironmentOperation(name string) *CreateEnvironmentOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &CreateEnvironmentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateEnvironmentOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.Environment, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp cxpb.Environment + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateEnvironmentOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.Environment, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp cxpb.Environment + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateEnvironmentOperation) Metadata() (*structpb.Struct, error) { + var meta structpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateEnvironmentOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *CreateEnvironmentOperation) Name() string { + return op.lro.Name() +} + +// DeployFlowOperation manages a long-running operation from DeployFlow. +type DeployFlowOperation struct { + lro *longrunning.Operation + pollPath string +} + +// DeployFlowOperation returns a new DeployFlowOperation from a given name. +// The name must be that of a previously created DeployFlowOperation, possibly from a different process. +func (c *environmentsGRPCClient) DeployFlowOperation(name string) *DeployFlowOperation { + return &DeployFlowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// DeployFlowOperation returns a new DeployFlowOperation from a given name. +// The name must be that of a previously created DeployFlowOperation, possibly from a different process. +func (c *environmentsRESTClient) DeployFlowOperation(name string) *DeployFlowOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &DeployFlowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *DeployFlowOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.DeployFlowResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp cxpb.DeployFlowResponse + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. // // Poll also fetches the latest metadata, which can be retrieved by Metadata. // @@ -986,6 +2165,7 @@ func (op *DeployFlowOperation) Wait(ctx context.Context, opts ...gax.CallOption) // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeployFlowOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.DeployFlowResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp cxpb.DeployFlowResponse if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1023,7 +2203,8 @@ func (op *DeployFlowOperation) Name() string { // RunContinuousTestOperation manages a long-running operation from RunContinuousTest. type RunContinuousTestOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // RunContinuousTestOperation returns a new RunContinuousTestOperation from a given name. @@ -1034,10 +2215,21 @@ func (c *environmentsGRPCClient) RunContinuousTestOperation(name string) *RunCon } } +// RunContinuousTestOperation returns a new RunContinuousTestOperation from a given name. +// The name must be that of a previously created RunContinuousTestOperation, possibly from a different process. +func (c *environmentsRESTClient) RunContinuousTestOperation(name string) *RunContinuousTestOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &RunContinuousTestOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *RunContinuousTestOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.RunContinuousTestResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp cxpb.RunContinuousTestResponse if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1055,6 +2247,7 @@ func (op *RunContinuousTestOperation) Wait(ctx context.Context, opts ...gax.Call // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *RunContinuousTestOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.RunContinuousTestResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp cxpb.RunContinuousTestResponse if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1092,7 +2285,8 @@ func (op *RunContinuousTestOperation) Name() string { // UpdateEnvironmentOperation manages a long-running operation from UpdateEnvironment. type UpdateEnvironmentOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UpdateEnvironmentOperation returns a new UpdateEnvironmentOperation from a given name. @@ -1103,10 +2297,21 @@ func (c *environmentsGRPCClient) UpdateEnvironmentOperation(name string) *Update } } +// UpdateEnvironmentOperation returns a new UpdateEnvironmentOperation from a given name. +// The name must be that of a previously created UpdateEnvironmentOperation, possibly from a different process. +func (c *environmentsRESTClient) UpdateEnvironmentOperation(name string) *UpdateEnvironmentOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &UpdateEnvironmentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UpdateEnvironmentOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.Environment, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp cxpb.Environment if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1124,6 +2329,7 @@ func (op *UpdateEnvironmentOperation) Wait(ctx context.Context, opts ...gax.Call // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UpdateEnvironmentOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.Environment, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp cxpb.Environment if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/dialogflow/cx/apiv3beta1/environments_client_example_test.go b/dialogflow/cx/apiv3beta1/environments_client_example_test.go index 7b4ef26e9930..6a8af72e7b9c 100644 --- a/dialogflow/cx/apiv3beta1/environments_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/environments_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewEnvironmentsClient() { _ = c } +func ExampleNewEnvironmentsRESTClient() { + ctx := context.Background() + c, err := cx.NewEnvironmentsRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleEnvironmentsClient_ListEnvironments() { ctx := context.Background() c, err := cx.NewEnvironmentsClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/experiments_client.go b/dialogflow/cx/apiv3beta1/experiments_client.go index 0713218072cf..c2f50ff2ede3 100644 --- a/dialogflow/cx/apiv3beta1/experiments_client.go +++ b/dialogflow/cx/apiv3beta1/experiments_client.go @@ -17,23 +17,29 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -154,6 +160,86 @@ func defaultExperimentsCallOptions() *ExperimentsCallOptions { } } +func defaultExperimentsRESTCallOptions() *ExperimentsCallOptions { + return &ExperimentsCallOptions{ + ListExperiments: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetExperiment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateExperiment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateExperiment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteExperiment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + StartExperiment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + StopExperiment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalExperimentsClient is an interface that defines the methods available from Dialogflow API. type internalExperimentsClient interface { Close() error @@ -355,6 +441,74 @@ func (c *experimentsGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type experimentsRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing ExperimentsClient + CallOptions **ExperimentsCallOptions +} + +// NewExperimentsRESTClient creates a new experiments rest client. +// +// Service for managing Experiments. +func NewExperimentsRESTClient(ctx context.Context, opts ...option.ClientOption) (*ExperimentsClient, error) { + clientOpts := append(defaultExperimentsRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultExperimentsRESTCallOptions() + c := &experimentsRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &ExperimentsClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultExperimentsRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *experimentsRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *experimentsRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *experimentsRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *experimentsGRPCClient) ListExperiments(ctx context.Context, req *cxpb.ListExperimentsRequest, opts ...gax.CallOption) *ExperimentIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -665,6 +819,749 @@ func (c *experimentsGRPCClient) ListOperations(ctx context.Context, req *longrun return it } +// ListExperiments returns the list of all experiments in the specified Environment. +func (c *experimentsRESTClient) ListExperiments(ctx context.Context, req *cxpb.ListExperimentsRequest, opts ...gax.CallOption) *ExperimentIterator { + it := &ExperimentIterator{} + req = proto.Clone(req).(*cxpb.ListExperimentsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.Experiment, string, error) { + resp := &cxpb.ListExperimentsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/experiments", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetExperiments(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetExperiment retrieves the specified Experiment. +func (c *experimentsRESTClient) GetExperiment(ctx context.Context, req *cxpb.GetExperimentRequest, opts ...gax.CallOption) (*cxpb.Experiment, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetExperiment[0:len((*c.CallOptions).GetExperiment):len((*c.CallOptions).GetExperiment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Experiment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateExperiment creates an Experiment in the specified Environment. +func (c *experimentsRESTClient) CreateExperiment(ctx context.Context, req *cxpb.CreateExperimentRequest, opts ...gax.CallOption) (*cxpb.Experiment, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetExperiment() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/experiments", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateExperiment[0:len((*c.CallOptions).CreateExperiment):len((*c.CallOptions).CreateExperiment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Experiment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateExperiment updates the specified Experiment. +func (c *experimentsRESTClient) UpdateExperiment(ctx context.Context, req *cxpb.UpdateExperimentRequest, opts ...gax.CallOption) (*cxpb.Experiment, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetExperiment() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetExperiment().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "experiment.name", url.QueryEscape(req.GetExperiment().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateExperiment[0:len((*c.CallOptions).UpdateExperiment):len((*c.CallOptions).UpdateExperiment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Experiment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteExperiment deletes the specified Experiment. +func (c *experimentsRESTClient) DeleteExperiment(ctx context.Context, req *cxpb.DeleteExperimentRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// StartExperiment starts the specified Experiment. This rpc only changes the state of +// experiment from PENDING to RUNNING. +func (c *experimentsRESTClient) StartExperiment(ctx context.Context, req *cxpb.StartExperimentRequest, opts ...gax.CallOption) (*cxpb.Experiment, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:start", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).StartExperiment[0:len((*c.CallOptions).StartExperiment):len((*c.CallOptions).StartExperiment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Experiment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// StopExperiment stops the specified Experiment. This rpc only changes the state of +// experiment from RUNNING to DONE. +func (c *experimentsRESTClient) StopExperiment(ctx context.Context, req *cxpb.StopExperimentRequest, opts ...gax.CallOption) (*cxpb.Experiment, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:stop", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).StopExperiment[0:len((*c.CallOptions).StopExperiment):len((*c.CallOptions).StopExperiment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Experiment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetLocation gets information about a location. +func (c *experimentsRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *experimentsRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *experimentsRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *experimentsRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *experimentsRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // ExperimentIterator manages a stream of *cxpb.Experiment. type ExperimentIterator struct { items []*cxpb.Experiment diff --git a/dialogflow/cx/apiv3beta1/experiments_client_example_test.go b/dialogflow/cx/apiv3beta1/experiments_client_example_test.go index b6306e7508bc..bbcd0f9d2082 100644 --- a/dialogflow/cx/apiv3beta1/experiments_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/experiments_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewExperimentsClient() { _ = c } +func ExampleNewExperimentsRESTClient() { + ctx := context.Background() + c, err := cx.NewExperimentsRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleExperimentsClient_ListExperiments() { ctx := context.Background() c, err := cx.NewExperimentsClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/flows_client.go b/dialogflow/cx/apiv3beta1/flows_client.go index 12f4a88caf62..bc1f5eb6ce0c 100644 --- a/dialogflow/cx/apiv3beta1/flows_client.go +++ b/dialogflow/cx/apiv3beta1/flows_client.go @@ -17,9 +17,12 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" @@ -27,16 +30,19 @@ import ( lroauto "cloud.google.com/go/longrunning/autogen" structpb "github.com/golang/protobuf/ptypes/struct" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -193,6 +199,116 @@ func defaultFlowsCallOptions() *FlowsCallOptions { } } +func defaultFlowsRESTCallOptions() *FlowsCallOptions { + return &FlowsCallOptions{ + CreateFlow: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteFlow: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListFlows: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetFlow: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateFlow: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + TrainFlow: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ValidateFlow: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetFlowValidationResult: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ImportFlow: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ExportFlow: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalFlowsClient is an interface that defines the methods available from Dialogflow API. type internalFlowsClient interface { Close() error @@ -503,6 +619,89 @@ func (c *flowsGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type flowsRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing FlowsClient + CallOptions **FlowsCallOptions +} + +// NewFlowsRESTClient creates a new flows rest client. +// +// Service for managing Flows. +func NewFlowsRESTClient(ctx context.Context, opts ...option.ClientOption) (*FlowsClient, error) { + clientOpts := append(defaultFlowsRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultFlowsRESTCallOptions() + c := &flowsRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &FlowsClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultFlowsRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *flowsRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *flowsRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *flowsRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *flowsGRPCClient) CreateFlow(ctx context.Context, req *cxpb.CreateFlowRequest, opts ...gax.CallOption) (*cxpb.Flow, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -885,122 +1084,1157 @@ func (c *flowsGRPCClient) ListOperations(ctx context.Context, req *longrunningpb return it } -// ExportFlowOperation manages a long-running operation from ExportFlow. -type ExportFlowOperation struct { - lro *longrunning.Operation -} - -// ExportFlowOperation returns a new ExportFlowOperation from a given name. -// The name must be that of a previously created ExportFlowOperation, possibly from a different process. -func (c *flowsGRPCClient) ExportFlowOperation(name string) *ExportFlowOperation { - return &ExportFlowOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), - } -} - -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// CreateFlow creates a flow in the specified agent. // -// See documentation of Poll for error-handling information. -func (op *ExportFlowOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.ExportFlowResponse, error) { - var resp cxpb.ExportFlowResponse - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *flowsRESTClient) CreateFlow(ctx context.Context, req *cxpb.CreateFlowRequest, opts ...gax.CallOption) (*cxpb.Flow, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetFlow() + jsonReq, err := m.Marshal(body) + if err != nil { return nil, err } - return &resp, nil -} -// Poll fetches the latest state of the long-running operation. -// -// Poll also fetches the latest metadata, which can be retrieved by Metadata. -// -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *ExportFlowOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.ExportFlowResponse, error) { - var resp cxpb.ExportFlowResponse - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - if !op.Done() { - return nil, nil - } - return &resp, nil -} + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/flows", req.GetParent()) -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. -// If the metadata is not available, the returned metadata and error are both nil. -func (op *ExportFlowOperation) Metadata() (*structpb.Struct, error) { - var meta structpb.Struct - if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { - return nil, nil - } else if err != nil { - return nil, err + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) } - return &meta, nil -} -// Done reports whether the long-running operation has completed. -func (op *ExportFlowOperation) Done() bool { - return op.lro.Done() -} + baseUrl.RawQuery = params.Encode() -// Name returns the name of the long-running operation. -// The name is assigned by the server and is unique within the service from which the operation is created. -func (op *ExportFlowOperation) Name() string { - return op.lro.Name() -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) -// ImportFlowOperation manages a long-running operation from ImportFlow. -type ImportFlowOperation struct { - lro *longrunning.Operation -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateFlow[0:len((*c.CallOptions).CreateFlow):len((*c.CallOptions).CreateFlow)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Flow{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// ImportFlowOperation returns a new ImportFlowOperation from a given name. -// The name must be that of a previously created ImportFlowOperation, possibly from a different process. -func (c *flowsGRPCClient) ImportFlowOperation(name string) *ImportFlowOperation { - return &ImportFlowOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), - } -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. -// -// See documentation of Poll for error-handling information. -func (op *ImportFlowOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.ImportFlowResponse, error) { - var resp cxpb.ImportFlowResponse - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { - return nil, err + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e } - return &resp, nil + return resp, nil } -// Poll fetches the latest state of the long-running operation. -// -// Poll also fetches the latest metadata, which can be retrieved by Metadata. -// -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *ImportFlowOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.ImportFlowResponse, error) { - var resp cxpb.ImportFlowResponse - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { - return nil, err +// DeleteFlow deletes a specified flow. +func (c *flowsRESTClient) DeleteFlow(ctx context.Context, req *cxpb.DeleteFlowRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err } - if !op.Done() { - return nil, nil + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetForce() { + params.Add("force", fmt.Sprintf("%v", req.GetForce())) } - return &resp, nil -} -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// ListFlows returns the list of all flows in the specified agent. +func (c *flowsRESTClient) ListFlows(ctx context.Context, req *cxpb.ListFlowsRequest, opts ...gax.CallOption) *FlowIterator { + it := &FlowIterator{} + req = proto.Clone(req).(*cxpb.ListFlowsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.Flow, string, error) { + resp := &cxpb.ListFlowsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/flows", req.GetParent()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetFlows(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetFlow retrieves the specified flow. +func (c *flowsRESTClient) GetFlow(ctx context.Context, req *cxpb.GetFlowRequest, opts ...gax.CallOption) (*cxpb.Flow, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetFlow[0:len((*c.CallOptions).GetFlow):len((*c.CallOptions).GetFlow)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Flow{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateFlow updates the specified flow. +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *flowsRESTClient) UpdateFlow(ctx context.Context, req *cxpb.UpdateFlowRequest, opts ...gax.CallOption) (*cxpb.Flow, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetFlow() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetFlow().GetName()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "flow.name", url.QueryEscape(req.GetFlow().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateFlow[0:len((*c.CallOptions).UpdateFlow):len((*c.CallOptions).UpdateFlow)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Flow{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// TrainFlow trains the specified flow. Note that only the flow in ‘draft’ environment +// is trained. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: An empty Struct +// message (at https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#struct) +// +// response: An Empty +// message (at https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#empty) +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *flowsRESTClient) TrainFlow(ctx context.Context, req *cxpb.TrainFlowRequest, opts ...gax.CallOption) (*TrainFlowOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:train", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &TrainFlowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ValidateFlow validates the specified flow and creates or updates validation results. +// Please call this API after the training is completed to get the complete +// validation results. +func (c *flowsRESTClient) ValidateFlow(ctx context.Context, req *cxpb.ValidateFlowRequest, opts ...gax.CallOption) (*cxpb.FlowValidationResult, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:validate", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ValidateFlow[0:len((*c.CallOptions).ValidateFlow):len((*c.CallOptions).ValidateFlow)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.FlowValidationResult{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetFlowValidationResult gets the latest flow validation result. Flow validation is performed +// when ValidateFlow is called. +func (c *flowsRESTClient) GetFlowValidationResult(ctx context.Context, req *cxpb.GetFlowValidationResultRequest, opts ...gax.CallOption) (*cxpb.FlowValidationResult, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetFlowValidationResult[0:len((*c.CallOptions).GetFlowValidationResult):len((*c.CallOptions).GetFlowValidationResult)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.FlowValidationResult{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ImportFlow imports the specified flow to the specified agent from a binary file. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: An empty Struct +// message (at https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#struct) +// +// response: ImportFlowResponse +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *flowsRESTClient) ImportFlow(ctx context.Context, req *cxpb.ImportFlowRequest, opts ...gax.CallOption) (*ImportFlowOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/flows:import", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &ImportFlowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ExportFlow exports the specified flow to a binary file. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: An empty Struct +// message (at https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#struct) +// +// response: ExportFlowResponse +// +// Note that resources (e.g. intents, entities, webhooks) that the flow +// references will also be exported. +func (c *flowsRESTClient) ExportFlow(ctx context.Context, req *cxpb.ExportFlowRequest, opts ...gax.CallOption) (*ExportFlowOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:export", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &ExportFlowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// GetLocation gets information about a location. +func (c *flowsRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *flowsRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *flowsRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *flowsRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *flowsRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// ExportFlowOperation manages a long-running operation from ExportFlow. +type ExportFlowOperation struct { + lro *longrunning.Operation + pollPath string +} + +// ExportFlowOperation returns a new ExportFlowOperation from a given name. +// The name must be that of a previously created ExportFlowOperation, possibly from a different process. +func (c *flowsGRPCClient) ExportFlowOperation(name string) *ExportFlowOperation { + return &ExportFlowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// ExportFlowOperation returns a new ExportFlowOperation from a given name. +// The name must be that of a previously created ExportFlowOperation, possibly from a different process. +func (c *flowsRESTClient) ExportFlowOperation(name string) *ExportFlowOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &ExportFlowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *ExportFlowOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.ExportFlowResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp cxpb.ExportFlowResponse + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *ExportFlowOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.ExportFlowResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp cxpb.ExportFlowResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *ExportFlowOperation) Metadata() (*structpb.Struct, error) { + var meta structpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *ExportFlowOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *ExportFlowOperation) Name() string { + return op.lro.Name() +} + +// ImportFlowOperation manages a long-running operation from ImportFlow. +type ImportFlowOperation struct { + lro *longrunning.Operation + pollPath string +} + +// ImportFlowOperation returns a new ImportFlowOperation from a given name. +// The name must be that of a previously created ImportFlowOperation, possibly from a different process. +func (c *flowsGRPCClient) ImportFlowOperation(name string) *ImportFlowOperation { + return &ImportFlowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// ImportFlowOperation returns a new ImportFlowOperation from a given name. +// The name must be that of a previously created ImportFlowOperation, possibly from a different process. +func (c *flowsRESTClient) ImportFlowOperation(name string) *ImportFlowOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &ImportFlowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *ImportFlowOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.ImportFlowResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp cxpb.ImportFlowResponse + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *ImportFlowOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.ImportFlowResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp cxpb.ImportFlowResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. // If the metadata is not available, the returned metadata and error are both nil. func (op *ImportFlowOperation) Metadata() (*structpb.Struct, error) { var meta structpb.Struct @@ -1025,7 +2259,8 @@ func (op *ImportFlowOperation) Name() string { // TrainFlowOperation manages a long-running operation from TrainFlow. type TrainFlowOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // TrainFlowOperation returns a new TrainFlowOperation from a given name. @@ -1036,10 +2271,21 @@ func (c *flowsGRPCClient) TrainFlowOperation(name string) *TrainFlowOperation { } } +// TrainFlowOperation returns a new TrainFlowOperation from a given name. +// The name must be that of a previously created TrainFlowOperation, possibly from a different process. +func (c *flowsRESTClient) TrainFlowOperation(name string) *TrainFlowOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &TrainFlowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *TrainFlowOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1053,6 +2299,7 @@ func (op *TrainFlowOperation) Wait(ctx context.Context, opts ...gax.CallOption) // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *TrainFlowOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } diff --git a/dialogflow/cx/apiv3beta1/flows_client_example_test.go b/dialogflow/cx/apiv3beta1/flows_client_example_test.go index dacd8f603f42..4bf15e702f65 100644 --- a/dialogflow/cx/apiv3beta1/flows_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/flows_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewFlowsClient() { _ = c } +func ExampleNewFlowsRESTClient() { + ctx := context.Background() + c, err := cx.NewFlowsRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleFlowsClient_CreateFlow() { ctx := context.Background() c, err := cx.NewFlowsClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/gapic_metadata.json b/dialogflow/cx/apiv3beta1/gapic_metadata.json index c487ec492c29..d77afa460c81 100644 --- a/dialogflow/cx/apiv3beta1/gapic_metadata.json +++ b/dialogflow/cx/apiv3beta1/gapic_metadata.json @@ -81,6 +81,81 @@ ] } } + }, + "rest": { + "libraryClient": "AgentsClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateAgent": { + "methods": [ + "CreateAgent" + ] + }, + "DeleteAgent": { + "methods": [ + "DeleteAgent" + ] + }, + "ExportAgent": { + "methods": [ + "ExportAgent" + ] + }, + "GetAgent": { + "methods": [ + "GetAgent" + ] + }, + "GetAgentValidationResult": { + "methods": [ + "GetAgentValidationResult" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListAgents": { + "methods": [ + "ListAgents" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "RestoreAgent": { + "methods": [ + "RestoreAgent" + ] + }, + "UpdateAgent": { + "methods": [ + "UpdateAgent" + ] + }, + "ValidateAgent": { + "methods": [ + "ValidateAgent" + ] + } + } } } }, @@ -125,6 +200,46 @@ ] } } + }, + "rest": { + "libraryClient": "ChangelogsClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "GetChangelog": { + "methods": [ + "GetChangelog" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListChangelogs": { + "methods": [ + "ListChangelogs" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + } + } } } }, @@ -169,32 +284,747 @@ ] } } + }, + "rest": { + "libraryClient": "DeploymentsClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "GetDeployment": { + "methods": [ + "GetDeployment" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListDeployments": { + "methods": [ + "ListDeployments" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + } + } + } + } + }, + "EntityTypes": { + "clients": { + "grpc": { + "libraryClient": "EntityTypesClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateEntityType": { + "methods": [ + "CreateEntityType" + ] + }, + "DeleteEntityType": { + "methods": [ + "DeleteEntityType" + ] + }, + "GetEntityType": { + "methods": [ + "GetEntityType" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListEntityTypes": { + "methods": [ + "ListEntityTypes" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "UpdateEntityType": { + "methods": [ + "UpdateEntityType" + ] + } + } + }, + "rest": { + "libraryClient": "EntityTypesClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateEntityType": { + "methods": [ + "CreateEntityType" + ] + }, + "DeleteEntityType": { + "methods": [ + "DeleteEntityType" + ] + }, + "GetEntityType": { + "methods": [ + "GetEntityType" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListEntityTypes": { + "methods": [ + "ListEntityTypes" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "UpdateEntityType": { + "methods": [ + "UpdateEntityType" + ] + } + } + } + } + }, + "Environments": { + "clients": { + "grpc": { + "libraryClient": "EnvironmentsClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateEnvironment": { + "methods": [ + "CreateEnvironment" + ] + }, + "DeleteEnvironment": { + "methods": [ + "DeleteEnvironment" + ] + }, + "DeployFlow": { + "methods": [ + "DeployFlow" + ] + }, + "GetEnvironment": { + "methods": [ + "GetEnvironment" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListContinuousTestResults": { + "methods": [ + "ListContinuousTestResults" + ] + }, + "ListEnvironments": { + "methods": [ + "ListEnvironments" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "LookupEnvironmentHistory": { + "methods": [ + "LookupEnvironmentHistory" + ] + }, + "RunContinuousTest": { + "methods": [ + "RunContinuousTest" + ] + }, + "UpdateEnvironment": { + "methods": [ + "UpdateEnvironment" + ] + } + } + }, + "rest": { + "libraryClient": "EnvironmentsClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateEnvironment": { + "methods": [ + "CreateEnvironment" + ] + }, + "DeleteEnvironment": { + "methods": [ + "DeleteEnvironment" + ] + }, + "DeployFlow": { + "methods": [ + "DeployFlow" + ] + }, + "GetEnvironment": { + "methods": [ + "GetEnvironment" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListContinuousTestResults": { + "methods": [ + "ListContinuousTestResults" + ] + }, + "ListEnvironments": { + "methods": [ + "ListEnvironments" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "LookupEnvironmentHistory": { + "methods": [ + "LookupEnvironmentHistory" + ] + }, + "RunContinuousTest": { + "methods": [ + "RunContinuousTest" + ] + }, + "UpdateEnvironment": { + "methods": [ + "UpdateEnvironment" + ] + } + } + } + } + }, + "Experiments": { + "clients": { + "grpc": { + "libraryClient": "ExperimentsClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateExperiment": { + "methods": [ + "CreateExperiment" + ] + }, + "DeleteExperiment": { + "methods": [ + "DeleteExperiment" + ] + }, + "GetExperiment": { + "methods": [ + "GetExperiment" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListExperiments": { + "methods": [ + "ListExperiments" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "StartExperiment": { + "methods": [ + "StartExperiment" + ] + }, + "StopExperiment": { + "methods": [ + "StopExperiment" + ] + }, + "UpdateExperiment": { + "methods": [ + "UpdateExperiment" + ] + } + } + }, + "rest": { + "libraryClient": "ExperimentsClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateExperiment": { + "methods": [ + "CreateExperiment" + ] + }, + "DeleteExperiment": { + "methods": [ + "DeleteExperiment" + ] + }, + "GetExperiment": { + "methods": [ + "GetExperiment" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListExperiments": { + "methods": [ + "ListExperiments" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "StartExperiment": { + "methods": [ + "StartExperiment" + ] + }, + "StopExperiment": { + "methods": [ + "StopExperiment" + ] + }, + "UpdateExperiment": { + "methods": [ + "UpdateExperiment" + ] + } + } + } + } + }, + "Flows": { + "clients": { + "grpc": { + "libraryClient": "FlowsClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateFlow": { + "methods": [ + "CreateFlow" + ] + }, + "DeleteFlow": { + "methods": [ + "DeleteFlow" + ] + }, + "ExportFlow": { + "methods": [ + "ExportFlow" + ] + }, + "GetFlow": { + "methods": [ + "GetFlow" + ] + }, + "GetFlowValidationResult": { + "methods": [ + "GetFlowValidationResult" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ImportFlow": { + "methods": [ + "ImportFlow" + ] + }, + "ListFlows": { + "methods": [ + "ListFlows" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "TrainFlow": { + "methods": [ + "TrainFlow" + ] + }, + "UpdateFlow": { + "methods": [ + "UpdateFlow" + ] + }, + "ValidateFlow": { + "methods": [ + "ValidateFlow" + ] + } + } + }, + "rest": { + "libraryClient": "FlowsClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateFlow": { + "methods": [ + "CreateFlow" + ] + }, + "DeleteFlow": { + "methods": [ + "DeleteFlow" + ] + }, + "ExportFlow": { + "methods": [ + "ExportFlow" + ] + }, + "GetFlow": { + "methods": [ + "GetFlow" + ] + }, + "GetFlowValidationResult": { + "methods": [ + "GetFlowValidationResult" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ImportFlow": { + "methods": [ + "ImportFlow" + ] + }, + "ListFlows": { + "methods": [ + "ListFlows" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "TrainFlow": { + "methods": [ + "TrainFlow" + ] + }, + "UpdateFlow": { + "methods": [ + "UpdateFlow" + ] + }, + "ValidateFlow": { + "methods": [ + "ValidateFlow" + ] + } + } + } + } + }, + "Intents": { + "clients": { + "grpc": { + "libraryClient": "IntentsClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateIntent": { + "methods": [ + "CreateIntent" + ] + }, + "DeleteIntent": { + "methods": [ + "DeleteIntent" + ] + }, + "GetIntent": { + "methods": [ + "GetIntent" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListIntents": { + "methods": [ + "ListIntents" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "UpdateIntent": { + "methods": [ + "UpdateIntent" + ] + } + } + }, + "rest": { + "libraryClient": "IntentsClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateIntent": { + "methods": [ + "CreateIntent" + ] + }, + "DeleteIntent": { + "methods": [ + "DeleteIntent" + ] + }, + "GetIntent": { + "methods": [ + "GetIntent" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListIntents": { + "methods": [ + "ListIntents" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "UpdateIntent": { + "methods": [ + "UpdateIntent" + ] + } + } } } }, - "EntityTypes": { + "Pages": { "clients": { "grpc": { - "libraryClient": "EntityTypesClient", + "libraryClient": "PagesClient", "rpcs": { "CancelOperation": { "methods": [ "CancelOperation" ] }, - "CreateEntityType": { - "methods": [ - "CreateEntityType" - ] - }, - "DeleteEntityType": { + "CreatePage": { "methods": [ - "DeleteEntityType" + "CreatePage" ] }, - "GetEntityType": { + "DeletePage": { "methods": [ - "GetEntityType" + "DeletePage" ] }, "GetLocation": { @@ -207,9 +1037,9 @@ "GetOperation" ] }, - "ListEntityTypes": { + "GetPage": { "methods": [ - "ListEntityTypes" + "GetPage" ] }, "ListLocations": { @@ -222,43 +1052,34 @@ "ListOperations" ] }, - "UpdateEntityType": { + "ListPages": { "methods": [ - "UpdateEntityType" + "ListPages" + ] + }, + "UpdatePage": { + "methods": [ + "UpdatePage" ] } } - } - } - }, - "Environments": { - "clients": { - "grpc": { - "libraryClient": "EnvironmentsClient", + }, + "rest": { + "libraryClient": "PagesClient", "rpcs": { "CancelOperation": { "methods": [ "CancelOperation" ] }, - "CreateEnvironment": { - "methods": [ - "CreateEnvironment" - ] - }, - "DeleteEnvironment": { - "methods": [ - "DeleteEnvironment" - ] - }, - "DeployFlow": { + "CreatePage": { "methods": [ - "DeployFlow" + "CreatePage" ] }, - "GetEnvironment": { + "DeletePage": { "methods": [ - "GetEnvironment" + "DeletePage" ] }, "GetLocation": { @@ -271,14 +1092,9 @@ "GetOperation" ] }, - "ListContinuousTestResults": { - "methods": [ - "ListContinuousTestResults" - ] - }, - "ListEnvironments": { + "GetPage": { "methods": [ - "ListEnvironments" + "GetPage" ] }, "ListLocations": { @@ -291,48 +1107,38 @@ "ListOperations" ] }, - "LookupEnvironmentHistory": { - "methods": [ - "LookupEnvironmentHistory" - ] - }, - "RunContinuousTest": { + "ListPages": { "methods": [ - "RunContinuousTest" + "ListPages" ] }, - "UpdateEnvironment": { + "UpdatePage": { "methods": [ - "UpdateEnvironment" + "UpdatePage" ] } } } } }, - "Experiments": { + "SecuritySettingsService": { "clients": { "grpc": { - "libraryClient": "ExperimentsClient", + "libraryClient": "SecuritySettingsClient", "rpcs": { "CancelOperation": { "methods": [ "CancelOperation" ] }, - "CreateExperiment": { - "methods": [ - "CreateExperiment" - ] - }, - "DeleteExperiment": { + "CreateSecuritySettings": { "methods": [ - "DeleteExperiment" + "CreateSecuritySettings" ] }, - "GetExperiment": { + "DeleteSecuritySettings": { "methods": [ - "GetExperiment" + "DeleteSecuritySettings" ] }, "GetLocation": { @@ -345,9 +1151,9 @@ "GetOperation" ] }, - "ListExperiments": { + "GetSecuritySettings": { "methods": [ - "ListExperiments" + "GetSecuritySettings" ] }, "ListLocations": { @@ -360,58 +1166,34 @@ "ListOperations" ] }, - "StartExperiment": { - "methods": [ - "StartExperiment" - ] - }, - "StopExperiment": { + "ListSecuritySettings": { "methods": [ - "StopExperiment" + "ListSecuritySettings" ] }, - "UpdateExperiment": { + "UpdateSecuritySettings": { "methods": [ - "UpdateExperiment" + "UpdateSecuritySettings" ] } } - } - } - }, - "Flows": { - "clients": { - "grpc": { - "libraryClient": "FlowsClient", + }, + "rest": { + "libraryClient": "SecuritySettingsClient", "rpcs": { "CancelOperation": { "methods": [ "CancelOperation" ] }, - "CreateFlow": { - "methods": [ - "CreateFlow" - ] - }, - "DeleteFlow": { - "methods": [ - "DeleteFlow" - ] - }, - "ExportFlow": { - "methods": [ - "ExportFlow" - ] - }, - "GetFlow": { + "CreateSecuritySettings": { "methods": [ - "GetFlow" + "CreateSecuritySettings" ] }, - "GetFlowValidationResult": { + "DeleteSecuritySettings": { "methods": [ - "GetFlowValidationResult" + "DeleteSecuritySettings" ] }, "GetLocation": { @@ -424,14 +1206,9 @@ "GetOperation" ] }, - "ImportFlow": { - "methods": [ - "ImportFlow" - ] - }, - "ListFlows": { + "GetSecuritySettings": { "methods": [ - "ListFlows" + "GetSecuritySettings" ] }, "ListLocations": { @@ -444,48 +1221,38 @@ "ListOperations" ] }, - "TrainFlow": { - "methods": [ - "TrainFlow" - ] - }, - "UpdateFlow": { + "ListSecuritySettings": { "methods": [ - "UpdateFlow" + "ListSecuritySettings" ] }, - "ValidateFlow": { + "UpdateSecuritySettings": { "methods": [ - "ValidateFlow" + "UpdateSecuritySettings" ] } } } } }, - "Intents": { + "SessionEntityTypes": { "clients": { "grpc": { - "libraryClient": "IntentsClient", + "libraryClient": "SessionEntityTypesClient", "rpcs": { "CancelOperation": { "methods": [ "CancelOperation" ] }, - "CreateIntent": { - "methods": [ - "CreateIntent" - ] - }, - "DeleteIntent": { + "CreateSessionEntityType": { "methods": [ - "DeleteIntent" + "CreateSessionEntityType" ] }, - "GetIntent": { + "DeleteSessionEntityType": { "methods": [ - "GetIntent" + "DeleteSessionEntityType" ] }, "GetLocation": { @@ -498,9 +1265,9 @@ "GetOperation" ] }, - "ListIntents": { + "GetSessionEntityType": { "methods": [ - "ListIntents" + "GetSessionEntityType" ] }, "ListLocations": { @@ -513,33 +1280,34 @@ "ListOperations" ] }, - "UpdateIntent": { + "ListSessionEntityTypes": { "methods": [ - "UpdateIntent" + "ListSessionEntityTypes" + ] + }, + "UpdateSessionEntityType": { + "methods": [ + "UpdateSessionEntityType" ] } } - } - } - }, - "Pages": { - "clients": { - "grpc": { - "libraryClient": "PagesClient", + }, + "rest": { + "libraryClient": "SessionEntityTypesClient", "rpcs": { "CancelOperation": { "methods": [ "CancelOperation" ] }, - "CreatePage": { + "CreateSessionEntityType": { "methods": [ - "CreatePage" + "CreateSessionEntityType" ] }, - "DeletePage": { + "DeleteSessionEntityType": { "methods": [ - "DeletePage" + "DeleteSessionEntityType" ] }, "GetLocation": { @@ -552,9 +1320,9 @@ "GetOperation" ] }, - "GetPage": { + "GetSessionEntityType": { "methods": [ - "GetPage" + "GetSessionEntityType" ] }, "ListLocations": { @@ -567,38 +1335,38 @@ "ListOperations" ] }, - "ListPages": { + "ListSessionEntityTypes": { "methods": [ - "ListPages" + "ListSessionEntityTypes" ] }, - "UpdatePage": { + "UpdateSessionEntityType": { "methods": [ - "UpdatePage" + "UpdateSessionEntityType" ] } } } } }, - "SecuritySettingsService": { + "Sessions": { "clients": { "grpc": { - "libraryClient": "SecuritySettingsClient", + "libraryClient": "SessionsClient", "rpcs": { "CancelOperation": { "methods": [ "CancelOperation" ] }, - "CreateSecuritySettings": { + "DetectIntent": { "methods": [ - "CreateSecuritySettings" + "DetectIntent" ] }, - "DeleteSecuritySettings": { + "FulfillIntent": { "methods": [ - "DeleteSecuritySettings" + "FulfillIntent" ] }, "GetLocation": { @@ -611,11 +1379,6 @@ "GetOperation" ] }, - "GetSecuritySettings": { - "methods": [ - "GetSecuritySettings" - ] - }, "ListLocations": { "methods": [ "ListLocations" @@ -626,38 +1389,34 @@ "ListOperations" ] }, - "ListSecuritySettings": { + "MatchIntent": { "methods": [ - "ListSecuritySettings" + "MatchIntent" ] }, - "UpdateSecuritySettings": { + "StreamingDetectIntent": { "methods": [ - "UpdateSecuritySettings" + "StreamingDetectIntent" ] } } - } - } - }, - "SessionEntityTypes": { - "clients": { - "grpc": { - "libraryClient": "SessionEntityTypesClient", + }, + "rest": { + "libraryClient": "SessionsClient", "rpcs": { "CancelOperation": { "methods": [ "CancelOperation" ] }, - "CreateSessionEntityType": { + "DetectIntent": { "methods": [ - "CreateSessionEntityType" + "DetectIntent" ] }, - "DeleteSessionEntityType": { + "FulfillIntent": { "methods": [ - "DeleteSessionEntityType" + "FulfillIntent" ] }, "GetLocation": { @@ -670,11 +1429,6 @@ "GetOperation" ] }, - "GetSessionEntityType": { - "methods": [ - "GetSessionEntityType" - ] - }, "ListLocations": { "methods": [ "ListLocations" @@ -685,38 +1439,53 @@ "ListOperations" ] }, - "ListSessionEntityTypes": { + "MatchIntent": { "methods": [ - "ListSessionEntityTypes" + "MatchIntent" ] }, - "UpdateSessionEntityType": { + "StreamingDetectIntent": { "methods": [ - "UpdateSessionEntityType" + "StreamingDetectIntent" ] } } } } }, - "Sessions": { + "TestCases": { "clients": { "grpc": { - "libraryClient": "SessionsClient", + "libraryClient": "TestCasesClient", "rpcs": { + "BatchDeleteTestCases": { + "methods": [ + "BatchDeleteTestCases" + ] + }, + "BatchRunTestCases": { + "methods": [ + "BatchRunTestCases" + ] + }, + "CalculateCoverage": { + "methods": [ + "CalculateCoverage" + ] + }, "CancelOperation": { "methods": [ "CancelOperation" ] }, - "DetectIntent": { + "CreateTestCase": { "methods": [ - "DetectIntent" + "CreateTestCase" ] }, - "FulfillIntent": { + "ExportTestCases": { "methods": [ - "FulfillIntent" + "ExportTestCases" ] }, "GetLocation": { @@ -729,6 +1498,21 @@ "GetOperation" ] }, + "GetTestCase": { + "methods": [ + "GetTestCase" + ] + }, + "GetTestCaseResult": { + "methods": [ + "GetTestCaseResult" + ] + }, + "ImportTestCases": { + "methods": [ + "ImportTestCases" + ] + }, "ListLocations": { "methods": [ "ListLocations" @@ -739,23 +1523,29 @@ "ListOperations" ] }, - "MatchIntent": { + "ListTestCaseResults": { "methods": [ - "MatchIntent" + "ListTestCaseResults" ] }, - "StreamingDetectIntent": { + "ListTestCases": { "methods": [ - "StreamingDetectIntent" + "ListTestCases" + ] + }, + "RunTestCase": { + "methods": [ + "RunTestCase" + ] + }, + "UpdateTestCase": { + "methods": [ + "UpdateTestCase" ] } } - } - } - }, - "TestCases": { - "clients": { - "grpc": { + }, + "rest": { "libraryClient": "TestCasesClient", "rpcs": { "BatchDeleteTestCases": { @@ -903,6 +1693,61 @@ ] } } + }, + "rest": { + "libraryClient": "TransitionRouteGroupsClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateTransitionRouteGroup": { + "methods": [ + "CreateTransitionRouteGroup" + ] + }, + "DeleteTransitionRouteGroup": { + "methods": [ + "DeleteTransitionRouteGroup" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "GetTransitionRouteGroup": { + "methods": [ + "GetTransitionRouteGroup" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "ListTransitionRouteGroups": { + "methods": [ + "ListTransitionRouteGroups" + ] + }, + "UpdateTransitionRouteGroup": { + "methods": [ + "UpdateTransitionRouteGroup" + ] + } + } } } }, @@ -972,6 +1817,71 @@ ] } } + }, + "rest": { + "libraryClient": "VersionsClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CompareVersions": { + "methods": [ + "CompareVersions" + ] + }, + "CreateVersion": { + "methods": [ + "CreateVersion" + ] + }, + "DeleteVersion": { + "methods": [ + "DeleteVersion" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "GetVersion": { + "methods": [ + "GetVersion" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "ListVersions": { + "methods": [ + "ListVersions" + ] + }, + "LoadVersion": { + "methods": [ + "LoadVersion" + ] + }, + "UpdateVersion": { + "methods": [ + "UpdateVersion" + ] + } + } } } }, @@ -1031,6 +1941,61 @@ ] } } + }, + "rest": { + "libraryClient": "WebhooksClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateWebhook": { + "methods": [ + "CreateWebhook" + ] + }, + "DeleteWebhook": { + "methods": [ + "DeleteWebhook" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "GetWebhook": { + "methods": [ + "GetWebhook" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "ListWebhooks": { + "methods": [ + "ListWebhooks" + ] + }, + "UpdateWebhook": { + "methods": [ + "UpdateWebhook" + ] + } + } } } } diff --git a/dialogflow/cx/apiv3beta1/intents_client.go b/dialogflow/cx/apiv3beta1/intents_client.go index fb8f568c6b92..40c367c55f5b 100644 --- a/dialogflow/cx/apiv3beta1/intents_client.go +++ b/dialogflow/cx/apiv3beta1/intents_client.go @@ -17,23 +17,29 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -130,6 +136,66 @@ func defaultIntentsCallOptions() *IntentsCallOptions { } } +func defaultIntentsRESTCallOptions() *IntentsCallOptions { + return &IntentsCallOptions{ + ListIntents: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetIntent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateIntent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateIntent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteIntent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalIntentsClient is an interface that defines the methods available from Dialogflow API. type internalIntentsClient interface { Close() error @@ -329,6 +395,74 @@ func (c *intentsGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type intentsRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing IntentsClient + CallOptions **IntentsCallOptions +} + +// NewIntentsRESTClient creates a new intents rest client. +// +// Service for managing Intents. +func NewIntentsRESTClient(ctx context.Context, opts ...option.ClientOption) (*IntentsClient, error) { + clientOpts := append(defaultIntentsRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultIntentsRESTCallOptions() + c := &intentsRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &IntentsClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultIntentsRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *intentsRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *intentsRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *intentsRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *intentsGRPCClient) ListIntents(ctx context.Context, req *cxpb.ListIntentsRequest, opts ...gax.CallOption) *IntentIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -595,6 +729,664 @@ func (c *intentsGRPCClient) ListOperations(ctx context.Context, req *longrunning return it } +// ListIntents returns the list of all intents in the specified agent. +func (c *intentsRESTClient) ListIntents(ctx context.Context, req *cxpb.ListIntentsRequest, opts ...gax.CallOption) *IntentIterator { + it := &IntentIterator{} + req = proto.Clone(req).(*cxpb.ListIntentsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.Intent, string, error) { + resp := &cxpb.ListIntentsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/intents", req.GetParent()) + + params := url.Values{} + if req.GetIntentView() != 0 { + params.Add("intentView", fmt.Sprintf("%v", req.GetIntentView())) + } + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetIntents(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetIntent retrieves the specified intent. +func (c *intentsRESTClient) GetIntent(ctx context.Context, req *cxpb.GetIntentRequest, opts ...gax.CallOption) (*cxpb.Intent, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetIntent[0:len((*c.CallOptions).GetIntent):len((*c.CallOptions).GetIntent)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Intent{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateIntent creates an intent in the specified agent. +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *intentsRESTClient) CreateIntent(ctx context.Context, req *cxpb.CreateIntentRequest, opts ...gax.CallOption) (*cxpb.Intent, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetIntent() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/intents", req.GetParent()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateIntent[0:len((*c.CallOptions).CreateIntent):len((*c.CallOptions).CreateIntent)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Intent{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateIntent updates the specified intent. +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *intentsRESTClient) UpdateIntent(ctx context.Context, req *cxpb.UpdateIntentRequest, opts ...gax.CallOption) (*cxpb.Intent, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetIntent() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetIntent().GetName()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "intent.name", url.QueryEscape(req.GetIntent().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateIntent[0:len((*c.CallOptions).UpdateIntent):len((*c.CallOptions).UpdateIntent)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Intent{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteIntent deletes the specified intent. +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *intentsRESTClient) DeleteIntent(ctx context.Context, req *cxpb.DeleteIntentRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetLocation gets information about a location. +func (c *intentsRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *intentsRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *intentsRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *intentsRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *intentsRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // IntentIterator manages a stream of *cxpb.Intent. type IntentIterator struct { items []*cxpb.Intent diff --git a/dialogflow/cx/apiv3beta1/intents_client_example_test.go b/dialogflow/cx/apiv3beta1/intents_client_example_test.go index d584c762bf14..28da566900db 100644 --- a/dialogflow/cx/apiv3beta1/intents_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/intents_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewIntentsClient() { _ = c } +func ExampleNewIntentsRESTClient() { + ctx := context.Background() + c, err := cx.NewIntentsRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleIntentsClient_ListIntents() { ctx := context.Background() c, err := cx.NewIntentsClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/pages_client.go b/dialogflow/cx/apiv3beta1/pages_client.go index fba0a0a63a10..904ab14b48c8 100644 --- a/dialogflow/cx/apiv3beta1/pages_client.go +++ b/dialogflow/cx/apiv3beta1/pages_client.go @@ -17,23 +17,29 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -130,6 +136,66 @@ func defaultPagesCallOptions() *PagesCallOptions { } } +func defaultPagesRESTCallOptions() *PagesCallOptions { + return &PagesCallOptions{ + ListPages: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetPage: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreatePage: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdatePage: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeletePage: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalPagesClient is an interface that defines the methods available from Dialogflow API. type internalPagesClient interface { Close() error @@ -317,6 +383,74 @@ func (c *pagesGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type pagesRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing PagesClient + CallOptions **PagesCallOptions +} + +// NewPagesRESTClient creates a new pages rest client. +// +// Service for managing [Pages][google.cloud.dialogflow.cx.v3beta1.Page (at http://google.cloud.dialogflow.cx.v3beta1.Page)]. +func NewPagesRESTClient(ctx context.Context, opts ...option.ClientOption) (*PagesClient, error) { + clientOpts := append(defaultPagesRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultPagesRESTCallOptions() + c := &pagesRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &PagesClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultPagesRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *pagesRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *pagesRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *pagesRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *pagesGRPCClient) ListPages(ctx context.Context, req *cxpb.ListPagesRequest, opts ...gax.CallOption) *PageIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -583,6 +717,656 @@ func (c *pagesGRPCClient) ListOperations(ctx context.Context, req *longrunningpb return it } +// ListPages returns the list of all pages in the specified flow. +func (c *pagesRESTClient) ListPages(ctx context.Context, req *cxpb.ListPagesRequest, opts ...gax.CallOption) *PageIterator { + it := &PageIterator{} + req = proto.Clone(req).(*cxpb.ListPagesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.Page, string, error) { + resp := &cxpb.ListPagesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/pages", req.GetParent()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetPages(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetPage retrieves the specified page. +func (c *pagesRESTClient) GetPage(ctx context.Context, req *cxpb.GetPageRequest, opts ...gax.CallOption) (*cxpb.Page, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetPage[0:len((*c.CallOptions).GetPage):len((*c.CallOptions).GetPage)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Page{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreatePage creates a page in the specified flow. +func (c *pagesRESTClient) CreatePage(ctx context.Context, req *cxpb.CreatePageRequest, opts ...gax.CallOption) (*cxpb.Page, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetPage() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/pages", req.GetParent()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreatePage[0:len((*c.CallOptions).CreatePage):len((*c.CallOptions).CreatePage)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Page{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdatePage updates the specified page. +func (c *pagesRESTClient) UpdatePage(ctx context.Context, req *cxpb.UpdatePageRequest, opts ...gax.CallOption) (*cxpb.Page, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetPage() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetPage().GetName()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "page.name", url.QueryEscape(req.GetPage().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdatePage[0:len((*c.CallOptions).UpdatePage):len((*c.CallOptions).UpdatePage)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Page{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeletePage deletes the specified page. +func (c *pagesRESTClient) DeletePage(ctx context.Context, req *cxpb.DeletePageRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetForce() { + params.Add("force", fmt.Sprintf("%v", req.GetForce())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetLocation gets information about a location. +func (c *pagesRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *pagesRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *pagesRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *pagesRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *pagesRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // LocationIterator manages a stream of *locationpb.Location. type LocationIterator struct { items []*locationpb.Location diff --git a/dialogflow/cx/apiv3beta1/pages_client_example_test.go b/dialogflow/cx/apiv3beta1/pages_client_example_test.go index 6e2d0e311771..4fef9dc1e5fb 100644 --- a/dialogflow/cx/apiv3beta1/pages_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/pages_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewPagesClient() { _ = c } +func ExampleNewPagesRESTClient() { + ctx := context.Background() + c, err := cx.NewPagesRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExamplePagesClient_ListPages() { ctx := context.Background() c, err := cx.NewPagesClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/security_settings_client.go b/dialogflow/cx/apiv3beta1/security_settings_client.go index 91ba5319bfdd..2e836753eea6 100644 --- a/dialogflow/cx/apiv3beta1/security_settings_client.go +++ b/dialogflow/cx/apiv3beta1/security_settings_client.go @@ -17,23 +17,29 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -130,6 +136,66 @@ func defaultSecuritySettingsCallOptions() *SecuritySettingsCallOptions { } } +func defaultSecuritySettingsRESTCallOptions() *SecuritySettingsCallOptions { + return &SecuritySettingsCallOptions{ + CreateSecuritySettings: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetSecuritySettings: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateSecuritySettings: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListSecuritySettings: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteSecuritySettings: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalSecuritySettingsClient is an interface that defines the methods available from Dialogflow API. type internalSecuritySettingsClient interface { Close() error @@ -318,6 +384,74 @@ func (c *securitySettingsGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type securitySettingsRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing SecuritySettingsClient + CallOptions **SecuritySettingsCallOptions +} + +// NewSecuritySettingsRESTClient creates a new security settings service rest client. +// +// Service for managing security settings for Dialogflow. +func NewSecuritySettingsRESTClient(ctx context.Context, opts ...option.ClientOption) (*SecuritySettingsClient, error) { + clientOpts := append(defaultSecuritySettingsRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultSecuritySettingsRESTCallOptions() + c := &securitySettingsRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &SecuritySettingsClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultSecuritySettingsRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *securitySettingsRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *securitySettingsRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *securitySettingsRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *securitySettingsGRPCClient) CreateSecuritySettings(ctx context.Context, req *cxpb.CreateSecuritySettingsRequest, opts ...gax.CallOption) (*cxpb.SecuritySettings, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -584,6 +718,630 @@ func (c *securitySettingsGRPCClient) ListOperations(ctx context.Context, req *lo return it } +// CreateSecuritySettings create security settings in the specified location. +func (c *securitySettingsRESTClient) CreateSecuritySettings(ctx context.Context, req *cxpb.CreateSecuritySettingsRequest, opts ...gax.CallOption) (*cxpb.SecuritySettings, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetSecuritySettings() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/securitySettings", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateSecuritySettings[0:len((*c.CallOptions).CreateSecuritySettings):len((*c.CallOptions).CreateSecuritySettings)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.SecuritySettings{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetSecuritySettings retrieves the specified SecuritySettings. +// The returned settings may be stale by up to 1 minute. +func (c *securitySettingsRESTClient) GetSecuritySettings(ctx context.Context, req *cxpb.GetSecuritySettingsRequest, opts ...gax.CallOption) (*cxpb.SecuritySettings, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetSecuritySettings[0:len((*c.CallOptions).GetSecuritySettings):len((*c.CallOptions).GetSecuritySettings)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.SecuritySettings{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateSecuritySettings updates the specified SecuritySettings. +func (c *securitySettingsRESTClient) UpdateSecuritySettings(ctx context.Context, req *cxpb.UpdateSecuritySettingsRequest, opts ...gax.CallOption) (*cxpb.SecuritySettings, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetSecuritySettings() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetSecuritySettings().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "security_settings.name", url.QueryEscape(req.GetSecuritySettings().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateSecuritySettings[0:len((*c.CallOptions).UpdateSecuritySettings):len((*c.CallOptions).UpdateSecuritySettings)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.SecuritySettings{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListSecuritySettings returns the list of all security settings in the specified location. +func (c *securitySettingsRESTClient) ListSecuritySettings(ctx context.Context, req *cxpb.ListSecuritySettingsRequest, opts ...gax.CallOption) *SecuritySettingsIterator { + it := &SecuritySettingsIterator{} + req = proto.Clone(req).(*cxpb.ListSecuritySettingsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.SecuritySettings, string, error) { + resp := &cxpb.ListSecuritySettingsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/securitySettings", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetSecuritySettings(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// DeleteSecuritySettings deletes the specified SecuritySettings. +func (c *securitySettingsRESTClient) DeleteSecuritySettings(ctx context.Context, req *cxpb.DeleteSecuritySettingsRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetLocation gets information about a location. +func (c *securitySettingsRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *securitySettingsRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *securitySettingsRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *securitySettingsRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *securitySettingsRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // SecuritySettingsIterator manages a stream of *cxpb.SecuritySettings. type SecuritySettingsIterator struct { items []*cxpb.SecuritySettings diff --git a/dialogflow/cx/apiv3beta1/security_settings_client_example_test.go b/dialogflow/cx/apiv3beta1/security_settings_client_example_test.go index 0cc6a3ae1cf9..b20cbdcf7fcd 100644 --- a/dialogflow/cx/apiv3beta1/security_settings_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/security_settings_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewSecuritySettingsClient() { _ = c } +func ExampleNewSecuritySettingsRESTClient() { + ctx := context.Background() + c, err := cx.NewSecuritySettingsRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleSecuritySettingsClient_CreateSecuritySettings() { ctx := context.Background() c, err := cx.NewSecuritySettingsClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/session_entity_types_client.go b/dialogflow/cx/apiv3beta1/session_entity_types_client.go index 672e4e6f3c65..a872163ecbc1 100644 --- a/dialogflow/cx/apiv3beta1/session_entity_types_client.go +++ b/dialogflow/cx/apiv3beta1/session_entity_types_client.go @@ -17,23 +17,29 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -130,6 +136,66 @@ func defaultSessionEntityTypesCallOptions() *SessionEntityTypesCallOptions { } } +func defaultSessionEntityTypesRESTCallOptions() *SessionEntityTypesCallOptions { + return &SessionEntityTypesCallOptions{ + ListSessionEntityTypes: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetSessionEntityType: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateSessionEntityType: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateSessionEntityType: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteSessionEntityType: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalSessionEntityTypesClient is an interface that defines the methods available from Dialogflow API. type internalSessionEntityTypesClient interface { Close() error @@ -317,6 +383,74 @@ func (c *sessionEntityTypesGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type sessionEntityTypesRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing SessionEntityTypesClient + CallOptions **SessionEntityTypesCallOptions +} + +// NewSessionEntityTypesRESTClient creates a new session entity types rest client. +// +// Service for managing SessionEntityTypes. +func NewSessionEntityTypesRESTClient(ctx context.Context, opts ...option.ClientOption) (*SessionEntityTypesClient, error) { + clientOpts := append(defaultSessionEntityTypesRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultSessionEntityTypesRESTCallOptions() + c := &sessionEntityTypesRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &SessionEntityTypesClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultSessionEntityTypesRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *sessionEntityTypesRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *sessionEntityTypesRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *sessionEntityTypesRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *sessionEntityTypesGRPCClient) ListSessionEntityTypes(ctx context.Context, req *cxpb.ListSessionEntityTypesRequest, opts ...gax.CallOption) *SessionEntityTypeIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -583,6 +717,629 @@ func (c *sessionEntityTypesGRPCClient) ListOperations(ctx context.Context, req * return it } +// ListSessionEntityTypes returns the list of all session entity types in the specified session. +func (c *sessionEntityTypesRESTClient) ListSessionEntityTypes(ctx context.Context, req *cxpb.ListSessionEntityTypesRequest, opts ...gax.CallOption) *SessionEntityTypeIterator { + it := &SessionEntityTypeIterator{} + req = proto.Clone(req).(*cxpb.ListSessionEntityTypesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.SessionEntityType, string, error) { + resp := &cxpb.ListSessionEntityTypesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/entityTypes", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetSessionEntityTypes(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetSessionEntityType retrieves the specified session entity type. +func (c *sessionEntityTypesRESTClient) GetSessionEntityType(ctx context.Context, req *cxpb.GetSessionEntityTypeRequest, opts ...gax.CallOption) (*cxpb.SessionEntityType, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetSessionEntityType[0:len((*c.CallOptions).GetSessionEntityType):len((*c.CallOptions).GetSessionEntityType)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.SessionEntityType{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateSessionEntityType creates a session entity type. +func (c *sessionEntityTypesRESTClient) CreateSessionEntityType(ctx context.Context, req *cxpb.CreateSessionEntityTypeRequest, opts ...gax.CallOption) (*cxpb.SessionEntityType, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetSessionEntityType() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/entityTypes", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateSessionEntityType[0:len((*c.CallOptions).CreateSessionEntityType):len((*c.CallOptions).CreateSessionEntityType)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.SessionEntityType{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateSessionEntityType updates the specified session entity type. +func (c *sessionEntityTypesRESTClient) UpdateSessionEntityType(ctx context.Context, req *cxpb.UpdateSessionEntityTypeRequest, opts ...gax.CallOption) (*cxpb.SessionEntityType, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetSessionEntityType() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetSessionEntityType().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "session_entity_type.name", url.QueryEscape(req.GetSessionEntityType().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateSessionEntityType[0:len((*c.CallOptions).UpdateSessionEntityType):len((*c.CallOptions).UpdateSessionEntityType)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.SessionEntityType{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteSessionEntityType deletes the specified session entity type. +func (c *sessionEntityTypesRESTClient) DeleteSessionEntityType(ctx context.Context, req *cxpb.DeleteSessionEntityTypeRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetLocation gets information about a location. +func (c *sessionEntityTypesRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *sessionEntityTypesRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *sessionEntityTypesRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *sessionEntityTypesRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *sessionEntityTypesRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // SessionEntityTypeIterator manages a stream of *cxpb.SessionEntityType. type SessionEntityTypeIterator struct { items []*cxpb.SessionEntityType diff --git a/dialogflow/cx/apiv3beta1/session_entity_types_client_example_test.go b/dialogflow/cx/apiv3beta1/session_entity_types_client_example_test.go index 2f66994e223d..939829447d16 100644 --- a/dialogflow/cx/apiv3beta1/session_entity_types_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/session_entity_types_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewSessionEntityTypesClient() { _ = c } +func ExampleNewSessionEntityTypesRESTClient() { + ctx := context.Background() + c, err := cx.NewSessionEntityTypesRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleSessionEntityTypesClient_ListSessionEntityTypes() { ctx := context.Background() c, err := cx.NewSessionEntityTypesClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/sessions_client.go b/dialogflow/cx/apiv3beta1/sessions_client.go index 7a7e23cd7c99..5a56e87d46f5 100644 --- a/dialogflow/cx/apiv3beta1/sessions_client.go +++ b/dialogflow/cx/apiv3beta1/sessions_client.go @@ -17,23 +17,29 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -108,6 +114,47 @@ func defaultSessionsCallOptions() *SessionsCallOptions { } } +func defaultSessionsRESTCallOptions() *SessionsCallOptions { + return &SessionsCallOptions{ + DetectIntent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + StreamingDetectIntent: []gax.CallOption{}, + MatchIntent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + FulfillIntent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalSessionsClient is an interface that defines the methods available from Dialogflow API. type internalSessionsClient interface { Close() error @@ -309,6 +356,76 @@ func (c *sessionsGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type sessionsRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing SessionsClient + CallOptions **SessionsCallOptions +} + +// NewSessionsRESTClient creates a new sessions rest client. +// +// A session represents an interaction with a user. You retrieve user input +// and pass it to the DetectIntent method to determine +// user intent and respond. +func NewSessionsRESTClient(ctx context.Context, opts ...option.ClientOption) (*SessionsClient, error) { + clientOpts := append(defaultSessionsRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultSessionsRESTCallOptions() + c := &sessionsRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &SessionsClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultSessionsRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *sessionsRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *sessionsRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *sessionsRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *sessionsGRPCClient) DetectIntent(ctx context.Context, req *cxpb.DetectIntentRequest, opts ...gax.CallOption) (*cxpb.DetectIntentResponse, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 220000*time.Millisecond) @@ -526,3 +643,522 @@ func (c *sessionsGRPCClient) ListOperations(ctx context.Context, req *longrunnin return it } + +// DetectIntent processes a natural language query and returns structured, actionable data +// as a result. This method is not idempotent, because it may cause session +// entity types to be updated, which in turn might affect results of future +// queries. +// +// Note: Always use agent versions for production traffic. +// See Versions and +// environments (at https://cloud.google.com/dialogflow/cx/docs/concept/version). +func (c *sessionsRESTClient) DetectIntent(ctx context.Context, req *cxpb.DetectIntentRequest, opts ...gax.CallOption) (*cxpb.DetectIntentResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:detectIntent", req.GetSession()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "session", url.QueryEscape(req.GetSession()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).DetectIntent[0:len((*c.CallOptions).DetectIntent):len((*c.CallOptions).DetectIntent)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.DetectIntentResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// StreamingDetectIntent processes a natural language query in audio format in a streaming fashion +// and returns structured, actionable data as a result. This method is only +// available via the gRPC API (not REST). +// +// Note: Always use agent versions for production traffic. +// See Versions and +// environments (at https://cloud.google.com/dialogflow/cx/docs/concept/version). +func (c *sessionsRESTClient) StreamingDetectIntent(ctx context.Context, opts ...gax.CallOption) (cxpb.Sessions_StreamingDetectIntentClient, error) { + return nil, fmt.Errorf("StreamingDetectIntent not yet supported for REST clients") +} + +// MatchIntent returns preliminary intent match results, doesn’t change the session +// status. +func (c *sessionsRESTClient) MatchIntent(ctx context.Context, req *cxpb.MatchIntentRequest, opts ...gax.CallOption) (*cxpb.MatchIntentResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:matchIntent", req.GetSession()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "session", url.QueryEscape(req.GetSession()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).MatchIntent[0:len((*c.CallOptions).MatchIntent):len((*c.CallOptions).MatchIntent)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.MatchIntentResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// FulfillIntent fulfills a matched intent returned by MatchIntent. +// Must be called after MatchIntent, with input from +// MatchIntentResponse. Otherwise, the behavior is undefined. +func (c *sessionsRESTClient) FulfillIntent(ctx context.Context, req *cxpb.FulfillIntentRequest, opts ...gax.CallOption) (*cxpb.FulfillIntentResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:fulfillIntent", req.GetMatchIntentRequest().GetSession()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "match_intent_request.session", url.QueryEscape(req.GetMatchIntentRequest().GetSession()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).FulfillIntent[0:len((*c.CallOptions).FulfillIntent):len((*c.CallOptions).FulfillIntent)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.FulfillIntentResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetLocation gets information about a location. +func (c *sessionsRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *sessionsRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *sessionsRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *sessionsRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *sessionsRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} diff --git a/dialogflow/cx/apiv3beta1/sessions_client_example_test.go b/dialogflow/cx/apiv3beta1/sessions_client_example_test.go index 4c464d832994..ee3c96007478 100644 --- a/dialogflow/cx/apiv3beta1/sessions_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/sessions_client_example_test.go @@ -39,6 +39,18 @@ func ExampleNewSessionsClient() { _ = c } +func ExampleNewSessionsRESTClient() { + ctx := context.Background() + c, err := cx.NewSessionsRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleSessionsClient_DetectIntent() { ctx := context.Background() c, err := cx.NewSessionsClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/test_cases_client.go b/dialogflow/cx/apiv3beta1/test_cases_client.go index f5e18cad8c20..bc050b498c52 100644 --- a/dialogflow/cx/apiv3beta1/test_cases_client.go +++ b/dialogflow/cx/apiv3beta1/test_cases_client.go @@ -17,25 +17,31 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -216,6 +222,136 @@ func defaultTestCasesCallOptions() *TestCasesCallOptions { } } +func defaultTestCasesRESTCallOptions() *TestCasesCallOptions { + return &TestCasesCallOptions{ + ListTestCases: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + BatchDeleteTestCases: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetTestCase: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateTestCase: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateTestCase: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + RunTestCase: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + BatchRunTestCases: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CalculateCoverage: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ImportTestCases: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ExportTestCases: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListTestCaseResults: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetTestCaseResult: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalTestCasesClient is an interface that defines the methods available from Dialogflow API. type internalTestCasesClient interface { Close() error @@ -531,6 +667,90 @@ func (c *testCasesGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type testCasesRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing TestCasesClient + CallOptions **TestCasesCallOptions +} + +// NewTestCasesRESTClient creates a new test cases rest client. +// +// Service for managing [Test Cases][google.cloud.dialogflow.cx.v3beta1.TestCase] and +// [Test Case Results][google.cloud.dialogflow.cx.v3beta1.TestCaseResult]. +func NewTestCasesRESTClient(ctx context.Context, opts ...option.ClientOption) (*TestCasesClient, error) { + clientOpts := append(defaultTestCasesRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultTestCasesRESTCallOptions() + c := &testCasesRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &TestCasesClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultTestCasesRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *testCasesRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *testCasesRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *testCasesRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *testCasesGRPCClient) ListTestCases(ctx context.Context, req *cxpb.ListTestCasesRequest, opts ...gax.CallOption) *TestCaseIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -982,78 +1202,1212 @@ func (c *testCasesGRPCClient) ListOperations(ctx context.Context, req *longrunni return it } -// BatchRunTestCasesOperation manages a long-running operation from BatchRunTestCases. -type BatchRunTestCasesOperation struct { - lro *longrunning.Operation -} +// ListTestCases fetches a list of test cases for a given agent. +func (c *testCasesRESTClient) ListTestCases(ctx context.Context, req *cxpb.ListTestCasesRequest, opts ...gax.CallOption) *TestCaseIterator { + it := &TestCaseIterator{} + req = proto.Clone(req).(*cxpb.ListTestCasesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.TestCase, string, error) { + resp := &cxpb.ListTestCasesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/testCases", req.GetParent()) -// BatchRunTestCasesOperation returns a new BatchRunTestCasesOperation from a given name. -// The name must be that of a previously created BatchRunTestCasesOperation, possibly from a different process. -func (c *testCasesGRPCClient) BatchRunTestCasesOperation(name string) *BatchRunTestCasesOperation { - return &BatchRunTestCasesOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetTestCases(), resp.GetNextPageToken(), nil } -} -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. -// -// See documentation of Poll for error-handling information. -func (op *BatchRunTestCasesOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.BatchRunTestCasesResponse, error) { - var resp cxpb.BatchRunTestCasesResponse - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - return &resp, nil + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it } -// Poll fetches the latest state of the long-running operation. -// -// Poll also fetches the latest metadata, which can be retrieved by Metadata. -// -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *BatchRunTestCasesOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.BatchRunTestCasesResponse, error) { - var resp cxpb.BatchRunTestCasesResponse - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { - return nil, err - } - if !op.Done() { - return nil, nil +// BatchDeleteTestCases batch deletes test cases. +func (c *testCasesRESTClient) BatchDeleteTestCases(ctx context.Context, req *cxpb.BatchDeleteTestCasesRequest, opts ...gax.CallOption) error { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return err } - return &resp, nil -} -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. -// If the metadata is not available, the returned metadata and error are both nil. -func (op *BatchRunTestCasesOperation) Metadata() (*cxpb.BatchRunTestCasesMetadata, error) { - var meta cxpb.BatchRunTestCasesMetadata - if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { - return nil, nil - } else if err != nil { - return nil, err + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err } - return &meta, nil -} + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/testCases:batchDelete", req.GetParent()) -// Done reports whether the long-running operation has completed. -func (op *BatchRunTestCasesOperation) Done() bool { - return op.lro.Done() -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) -// Name returns the name of the long-running operation. -// The name is assigned by the server and is unique within the service from which the operation is created. -func (op *BatchRunTestCasesOperation) Name() string { - return op.lro.Name() -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// ExportTestCasesOperation manages a long-running operation from ExportTestCases. -type ExportTestCasesOperation struct { - lro *longrunning.Operation + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetTestCase gets a test case. +func (c *testCasesRESTClient) GetTestCase(ctx context.Context, req *cxpb.GetTestCaseRequest, opts ...gax.CallOption) (*cxpb.TestCase, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetTestCase[0:len((*c.CallOptions).GetTestCase):len((*c.CallOptions).GetTestCase)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.TestCase{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateTestCase creates a test case for the given agent. +func (c *testCasesRESTClient) CreateTestCase(ctx context.Context, req *cxpb.CreateTestCaseRequest, opts ...gax.CallOption) (*cxpb.TestCase, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetTestCase() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/testCases", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateTestCase[0:len((*c.CallOptions).CreateTestCase):len((*c.CallOptions).CreateTestCase)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.TestCase{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateTestCase updates the specified test case. +func (c *testCasesRESTClient) UpdateTestCase(ctx context.Context, req *cxpb.UpdateTestCaseRequest, opts ...gax.CallOption) (*cxpb.TestCase, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetTestCase() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetTestCase().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "test_case.name", url.QueryEscape(req.GetTestCase().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateTestCase[0:len((*c.CallOptions).UpdateTestCase):len((*c.CallOptions).UpdateTestCase)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.TestCase{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// RunTestCase kicks off a test case run. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: RunTestCaseMetadata +// +// response: RunTestCaseResponse +func (c *testCasesRESTClient) RunTestCase(ctx context.Context, req *cxpb.RunTestCaseRequest, opts ...gax.CallOption) (*RunTestCaseOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:run", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &RunTestCaseOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// BatchRunTestCases kicks off a batch run of test cases. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: BatchRunTestCasesMetadata +// +// response: BatchRunTestCasesResponse +func (c *testCasesRESTClient) BatchRunTestCases(ctx context.Context, req *cxpb.BatchRunTestCasesRequest, opts ...gax.CallOption) (*BatchRunTestCasesOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/testCases:batchRun", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &BatchRunTestCasesOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// CalculateCoverage calculates the test coverage for an agent. +func (c *testCasesRESTClient) CalculateCoverage(ctx context.Context, req *cxpb.CalculateCoverageRequest, opts ...gax.CallOption) (*cxpb.CalculateCoverageResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/testCases:calculateCoverage", req.GetAgent()) + + params := url.Values{} + params.Add("type", fmt.Sprintf("%v", req.GetType())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "agent", url.QueryEscape(req.GetAgent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CalculateCoverage[0:len((*c.CallOptions).CalculateCoverage):len((*c.CallOptions).CalculateCoverage)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.CalculateCoverageResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ImportTestCases imports the test cases from a Cloud Storage bucket or a local file. It +// always creates new test cases and won’t overwrite any existing ones. The +// provided ID in the imported test case is neglected. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: ImportTestCasesMetadata +// +// response: ImportTestCasesResponse +func (c *testCasesRESTClient) ImportTestCases(ctx context.Context, req *cxpb.ImportTestCasesRequest, opts ...gax.CallOption) (*ImportTestCasesOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/testCases:import", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &ImportTestCasesOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ExportTestCases exports the test cases under the agent to a Cloud Storage bucket or a local +// file. Filter can be applied to export a subset of test cases. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: ExportTestCasesMetadata +// +// response: ExportTestCasesResponse +func (c *testCasesRESTClient) ExportTestCases(ctx context.Context, req *cxpb.ExportTestCasesRequest, opts ...gax.CallOption) (*ExportTestCasesOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/testCases:export", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &ExportTestCasesOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ListTestCaseResults fetches a list of results for a given test case. +func (c *testCasesRESTClient) ListTestCaseResults(ctx context.Context, req *cxpb.ListTestCaseResultsRequest, opts ...gax.CallOption) *TestCaseResultIterator { + it := &TestCaseResultIterator{} + req = proto.Clone(req).(*cxpb.ListTestCaseResultsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.TestCaseResult, string, error) { + resp := &cxpb.ListTestCaseResultsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/results", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetTestCaseResults(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetTestCaseResult gets a test case result. +func (c *testCasesRESTClient) GetTestCaseResult(ctx context.Context, req *cxpb.GetTestCaseResultRequest, opts ...gax.CallOption) (*cxpb.TestCaseResult, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetTestCaseResult[0:len((*c.CallOptions).GetTestCaseResult):len((*c.CallOptions).GetTestCaseResult)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.TestCaseResult{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetLocation gets information about a location. +func (c *testCasesRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *testCasesRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *testCasesRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *testCasesRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *testCasesRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// BatchRunTestCasesOperation manages a long-running operation from BatchRunTestCases. +type BatchRunTestCasesOperation struct { + lro *longrunning.Operation + pollPath string +} + +// BatchRunTestCasesOperation returns a new BatchRunTestCasesOperation from a given name. +// The name must be that of a previously created BatchRunTestCasesOperation, possibly from a different process. +func (c *testCasesGRPCClient) BatchRunTestCasesOperation(name string) *BatchRunTestCasesOperation { + return &BatchRunTestCasesOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// BatchRunTestCasesOperation returns a new BatchRunTestCasesOperation from a given name. +// The name must be that of a previously created BatchRunTestCasesOperation, possibly from a different process. +func (c *testCasesRESTClient) BatchRunTestCasesOperation(name string) *BatchRunTestCasesOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &BatchRunTestCasesOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *BatchRunTestCasesOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.BatchRunTestCasesResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp cxpb.BatchRunTestCasesResponse + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *BatchRunTestCasesOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.BatchRunTestCasesResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp cxpb.BatchRunTestCasesResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *BatchRunTestCasesOperation) Metadata() (*cxpb.BatchRunTestCasesMetadata, error) { + var meta cxpb.BatchRunTestCasesMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *BatchRunTestCasesOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *BatchRunTestCasesOperation) Name() string { + return op.lro.Name() +} + +// ExportTestCasesOperation manages a long-running operation from ExportTestCases. +type ExportTestCasesOperation struct { + lro *longrunning.Operation + pollPath string } // ExportTestCasesOperation returns a new ExportTestCasesOperation from a given name. @@ -1064,10 +2418,21 @@ func (c *testCasesGRPCClient) ExportTestCasesOperation(name string) *ExportTestC } } +// ExportTestCasesOperation returns a new ExportTestCasesOperation from a given name. +// The name must be that of a previously created ExportTestCasesOperation, possibly from a different process. +func (c *testCasesRESTClient) ExportTestCasesOperation(name string) *ExportTestCasesOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &ExportTestCasesOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *ExportTestCasesOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.ExportTestCasesResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp cxpb.ExportTestCasesResponse if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1085,6 +2450,7 @@ func (op *ExportTestCasesOperation) Wait(ctx context.Context, opts ...gax.CallOp // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *ExportTestCasesOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.ExportTestCasesResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp cxpb.ExportTestCasesResponse if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1122,7 +2488,8 @@ func (op *ExportTestCasesOperation) Name() string { // ImportTestCasesOperation manages a long-running operation from ImportTestCases. type ImportTestCasesOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // ImportTestCasesOperation returns a new ImportTestCasesOperation from a given name. @@ -1133,10 +2500,21 @@ func (c *testCasesGRPCClient) ImportTestCasesOperation(name string) *ImportTestC } } +// ImportTestCasesOperation returns a new ImportTestCasesOperation from a given name. +// The name must be that of a previously created ImportTestCasesOperation, possibly from a different process. +func (c *testCasesRESTClient) ImportTestCasesOperation(name string) *ImportTestCasesOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &ImportTestCasesOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *ImportTestCasesOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.ImportTestCasesResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp cxpb.ImportTestCasesResponse if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1154,6 +2532,7 @@ func (op *ImportTestCasesOperation) Wait(ctx context.Context, opts ...gax.CallOp // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *ImportTestCasesOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.ImportTestCasesResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp cxpb.ImportTestCasesResponse if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1191,7 +2570,8 @@ func (op *ImportTestCasesOperation) Name() string { // RunTestCaseOperation manages a long-running operation from RunTestCase. type RunTestCaseOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // RunTestCaseOperation returns a new RunTestCaseOperation from a given name. @@ -1202,10 +2582,21 @@ func (c *testCasesGRPCClient) RunTestCaseOperation(name string) *RunTestCaseOper } } +// RunTestCaseOperation returns a new RunTestCaseOperation from a given name. +// The name must be that of a previously created RunTestCaseOperation, possibly from a different process. +func (c *testCasesRESTClient) RunTestCaseOperation(name string) *RunTestCaseOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &RunTestCaseOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *RunTestCaseOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.RunTestCaseResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp cxpb.RunTestCaseResponse if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1223,6 +2614,7 @@ func (op *RunTestCaseOperation) Wait(ctx context.Context, opts ...gax.CallOption // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *RunTestCaseOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.RunTestCaseResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp cxpb.RunTestCaseResponse if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/dialogflow/cx/apiv3beta1/test_cases_client_example_test.go b/dialogflow/cx/apiv3beta1/test_cases_client_example_test.go index 777ac50bd3ce..3a5660410745 100644 --- a/dialogflow/cx/apiv3beta1/test_cases_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/test_cases_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewTestCasesClient() { _ = c } +func ExampleNewTestCasesRESTClient() { + ctx := context.Background() + c, err := cx.NewTestCasesRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleTestCasesClient_ListTestCases() { ctx := context.Background() c, err := cx.NewTestCasesClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/transition_route_groups_client.go b/dialogflow/cx/apiv3beta1/transition_route_groups_client.go index 19b9cd839f6e..baa7dedf6bc5 100644 --- a/dialogflow/cx/apiv3beta1/transition_route_groups_client.go +++ b/dialogflow/cx/apiv3beta1/transition_route_groups_client.go @@ -17,23 +17,29 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -130,6 +136,66 @@ func defaultTransitionRouteGroupsCallOptions() *TransitionRouteGroupsCallOptions } } +func defaultTransitionRouteGroupsRESTCallOptions() *TransitionRouteGroupsCallOptions { + return &TransitionRouteGroupsCallOptions{ + ListTransitionRouteGroups: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetTransitionRouteGroup: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateTransitionRouteGroup: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateTransitionRouteGroup: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteTransitionRouteGroup: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalTransitionRouteGroupsClient is an interface that defines the methods available from Dialogflow API. type internalTransitionRouteGroupsClient interface { Close() error @@ -329,6 +395,74 @@ func (c *transitionRouteGroupsGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type transitionRouteGroupsRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing TransitionRouteGroupsClient + CallOptions **TransitionRouteGroupsCallOptions +} + +// NewTransitionRouteGroupsRESTClient creates a new transition route groups rest client. +// +// Service for managing TransitionRouteGroups. +func NewTransitionRouteGroupsRESTClient(ctx context.Context, opts ...option.ClientOption) (*TransitionRouteGroupsClient, error) { + clientOpts := append(defaultTransitionRouteGroupsRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultTransitionRouteGroupsRESTCallOptions() + c := &transitionRouteGroupsRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &TransitionRouteGroupsClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultTransitionRouteGroupsRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *transitionRouteGroupsRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *transitionRouteGroupsRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *transitionRouteGroupsRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *transitionRouteGroupsGRPCClient) ListTransitionRouteGroups(ctx context.Context, req *cxpb.ListTransitionRouteGroupsRequest, opts ...gax.CallOption) *TransitionRouteGroupIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -595,6 +729,668 @@ func (c *transitionRouteGroupsGRPCClient) ListOperations(ctx context.Context, re return it } +// ListTransitionRouteGroups returns the list of all transition route groups in the specified flow. +func (c *transitionRouteGroupsRESTClient) ListTransitionRouteGroups(ctx context.Context, req *cxpb.ListTransitionRouteGroupsRequest, opts ...gax.CallOption) *TransitionRouteGroupIterator { + it := &TransitionRouteGroupIterator{} + req = proto.Clone(req).(*cxpb.ListTransitionRouteGroupsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.TransitionRouteGroup, string, error) { + resp := &cxpb.ListTransitionRouteGroupsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/transitionRouteGroups", req.GetParent()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetTransitionRouteGroups(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetTransitionRouteGroup retrieves the specified TransitionRouteGroup. +func (c *transitionRouteGroupsRESTClient) GetTransitionRouteGroup(ctx context.Context, req *cxpb.GetTransitionRouteGroupRequest, opts ...gax.CallOption) (*cxpb.TransitionRouteGroup, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetTransitionRouteGroup[0:len((*c.CallOptions).GetTransitionRouteGroup):len((*c.CallOptions).GetTransitionRouteGroup)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.TransitionRouteGroup{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateTransitionRouteGroup creates an TransitionRouteGroup in the specified flow. +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *transitionRouteGroupsRESTClient) CreateTransitionRouteGroup(ctx context.Context, req *cxpb.CreateTransitionRouteGroupRequest, opts ...gax.CallOption) (*cxpb.TransitionRouteGroup, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetTransitionRouteGroup() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/transitionRouteGroups", req.GetParent()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateTransitionRouteGroup[0:len((*c.CallOptions).CreateTransitionRouteGroup):len((*c.CallOptions).CreateTransitionRouteGroup)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.TransitionRouteGroup{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateTransitionRouteGroup updates the specified TransitionRouteGroup. +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *transitionRouteGroupsRESTClient) UpdateTransitionRouteGroup(ctx context.Context, req *cxpb.UpdateTransitionRouteGroupRequest, opts ...gax.CallOption) (*cxpb.TransitionRouteGroup, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetTransitionRouteGroup() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetTransitionRouteGroup().GetName()) + + params := url.Values{} + if req.GetLanguageCode() != "" { + params.Add("languageCode", fmt.Sprintf("%v", req.GetLanguageCode())) + } + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "transition_route_group.name", url.QueryEscape(req.GetTransitionRouteGroup().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateTransitionRouteGroup[0:len((*c.CallOptions).UpdateTransitionRouteGroup):len((*c.CallOptions).UpdateTransitionRouteGroup)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.TransitionRouteGroup{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteTransitionRouteGroup deletes the specified TransitionRouteGroup. +// +// Note: You should always train a flow prior to sending it queries. See the +// training +// documentation (at https://cloud.google.com/dialogflow/cx/docs/concept/training). +func (c *transitionRouteGroupsRESTClient) DeleteTransitionRouteGroup(ctx context.Context, req *cxpb.DeleteTransitionRouteGroupRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetForce() { + params.Add("force", fmt.Sprintf("%v", req.GetForce())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetLocation gets information about a location. +func (c *transitionRouteGroupsRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *transitionRouteGroupsRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *transitionRouteGroupsRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *transitionRouteGroupsRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *transitionRouteGroupsRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // TransitionRouteGroupIterator manages a stream of *cxpb.TransitionRouteGroup. type TransitionRouteGroupIterator struct { items []*cxpb.TransitionRouteGroup diff --git a/dialogflow/cx/apiv3beta1/transition_route_groups_client_example_test.go b/dialogflow/cx/apiv3beta1/transition_route_groups_client_example_test.go index 9ea728da1e13..bb1b6ed5542b 100644 --- a/dialogflow/cx/apiv3beta1/transition_route_groups_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/transition_route_groups_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewTransitionRouteGroupsClient() { _ = c } +func ExampleNewTransitionRouteGroupsRESTClient() { + ctx := context.Background() + c, err := cx.NewTransitionRouteGroupsRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleTransitionRouteGroupsClient_ListTransitionRouteGroups() { ctx := context.Background() c, err := cx.NewTransitionRouteGroupsClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/versions_client.go b/dialogflow/cx/apiv3beta1/versions_client.go index bedccfe9876c..43cbbe15ce26 100644 --- a/dialogflow/cx/apiv3beta1/versions_client.go +++ b/dialogflow/cx/apiv3beta1/versions_client.go @@ -17,9 +17,12 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" @@ -27,16 +30,19 @@ import ( lroauto "cloud.google.com/go/longrunning/autogen" structpb "github.com/golang/protobuf/ptypes/struct" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -157,6 +163,86 @@ func defaultVersionsCallOptions() *VersionsCallOptions { } } +func defaultVersionsRESTCallOptions() *VersionsCallOptions { + return &VersionsCallOptions{ + ListVersions: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetVersion: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateVersion: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateVersion: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteVersion: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + LoadVersion: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CompareVersions: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalVersionsClient is an interface that defines the methods available from Dialogflow API. type internalVersionsClient interface { Close() error @@ -409,6 +495,89 @@ func (c *versionsGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type versionsRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing VersionsClient + CallOptions **VersionsCallOptions +} + +// NewVersionsRESTClient creates a new versions rest client. +// +// Service for managing Versions. +func NewVersionsRESTClient(ctx context.Context, opts ...option.ClientOption) (*VersionsClient, error) { + clientOpts := append(defaultVersionsRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultVersionsRESTCallOptions() + c := &versionsRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &VersionsClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultVersionsRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *versionsRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *versionsRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *versionsRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *versionsGRPCClient) ListVersions(ctx context.Context, req *cxpb.ListVersionsRequest, opts ...gax.CallOption) *VersionIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -723,85 +892,876 @@ func (c *versionsGRPCClient) ListOperations(ctx context.Context, req *longrunnin return it } -// CreateVersionOperation manages a long-running operation from CreateVersion. -type CreateVersionOperation struct { - lro *longrunning.Operation -} +// ListVersions returns the list of all versions in the specified Flow. +func (c *versionsRESTClient) ListVersions(ctx context.Context, req *cxpb.ListVersionsRequest, opts ...gax.CallOption) *VersionIterator { + it := &VersionIterator{} + req = proto.Clone(req).(*cxpb.ListVersionsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.Version, string, error) { + resp := &cxpb.ListVersionsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/versions", req.GetParent()) -// CreateVersionOperation returns a new CreateVersionOperation from a given name. -// The name must be that of a previously created CreateVersionOperation, possibly from a different process. -func (c *versionsGRPCClient) CreateVersionOperation(name string) *CreateVersionOperation { - return &CreateVersionOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetVersions(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it } -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. -// -// See documentation of Poll for error-handling information. -func (op *CreateVersionOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.Version, error) { - var resp cxpb.Version - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { +// GetVersion retrieves the specified Version. +func (c *versionsRESTClient) GetVersion(ctx context.Context, req *cxpb.GetVersionRequest, opts ...gax.CallOption) (*cxpb.Version, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - return &resp, nil + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetVersion[0:len((*c.CallOptions).GetVersion):len((*c.CallOptions).GetVersion)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Version{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil } -// Poll fetches the latest state of the long-running operation. +// CreateVersion creates a Version in the specified Flow. // -// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: // -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *CreateVersionOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.Version, error) { - var resp cxpb.Version - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { +// metadata: CreateVersionOperationMetadata +// +// response: Version +func (c *versionsRESTClient) CreateVersion(ctx context.Context, req *cxpb.CreateVersionRequest, opts ...gax.CallOption) (*CreateVersionOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetVersion() + jsonReq, err := m.Marshal(body) + if err != nil { return nil, err } - if !op.Done() { - return nil, nil - } - return &resp, nil -} -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. -// If the metadata is not available, the returned metadata and error are both nil. -func (op *CreateVersionOperation) Metadata() (*cxpb.CreateVersionOperationMetadata, error) { - var meta cxpb.CreateVersionOperationMetadata - if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { - return nil, nil - } else if err != nil { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - return &meta, nil -} + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/versions", req.GetParent()) -// Done reports whether the long-running operation has completed. -func (op *CreateVersionOperation) Done() bool { - return op.lro.Done() -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) -// Name returns the name of the long-running operation. -// The name is assigned by the server and is unique within the service from which the operation is created. -func (op *CreateVersionOperation) Name() string { - return op.lro.Name() -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// LoadVersionOperation manages a long-running operation from LoadVersion. -type LoadVersionOperation struct { - lro *longrunning.Operation -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// LoadVersionOperation returns a new LoadVersionOperation from a given name. -// The name must be that of a previously created LoadVersionOperation, possibly from a different process. -func (c *versionsGRPCClient) LoadVersionOperation(name string) *LoadVersionOperation { - return &LoadVersionOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &CreateVersionOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UpdateVersion updates the specified Version. +func (c *versionsRESTClient) UpdateVersion(ctx context.Context, req *cxpb.UpdateVersionRequest, opts ...gax.CallOption) (*cxpb.Version, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetVersion() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetVersion().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "version.name", url.QueryEscape(req.GetVersion().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateVersion[0:len((*c.CallOptions).UpdateVersion):len((*c.CallOptions).UpdateVersion)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Version{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteVersion deletes the specified Version. +func (c *versionsRESTClient) DeleteVersion(ctx context.Context, req *cxpb.DeleteVersionRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// LoadVersion loads resources in the specified version to the draft flow. +// +// This method is a long-running +// operation (at https://cloud.google.com/dialogflow/cx/docs/how/long-running-operation). +// The returned Operation type has the following method-specific fields: +// +// metadata: An empty Struct +// message (at https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#struct) +// +// response: An Empty +// message (at https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#empty) +func (c *versionsRESTClient) LoadVersion(ctx context.Context, req *cxpb.LoadVersionRequest, opts ...gax.CallOption) (*LoadVersionOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:load", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v3beta1/%s", resp.GetName()) + return &LoadVersionOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// CompareVersions compares the specified base version with target version. +func (c *versionsRESTClient) CompareVersions(ctx context.Context, req *cxpb.CompareVersionsRequest, opts ...gax.CallOption) (*cxpb.CompareVersionsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:compareVersions", req.GetBaseVersion()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "base_version", url.QueryEscape(req.GetBaseVersion()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CompareVersions[0:len((*c.CallOptions).CompareVersions):len((*c.CallOptions).CompareVersions)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.CompareVersionsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetLocation gets information about a location. +func (c *versionsRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *versionsRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *versionsRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *versionsRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *versionsRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CreateVersionOperation manages a long-running operation from CreateVersion. +type CreateVersionOperation struct { + lro *longrunning.Operation + pollPath string +} + +// CreateVersionOperation returns a new CreateVersionOperation from a given name. +// The name must be that of a previously created CreateVersionOperation, possibly from a different process. +func (c *versionsGRPCClient) CreateVersionOperation(name string) *CreateVersionOperation { + return &CreateVersionOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// CreateVersionOperation returns a new CreateVersionOperation from a given name. +// The name must be that of a previously created CreateVersionOperation, possibly from a different process. +func (c *versionsRESTClient) CreateVersionOperation(name string) *CreateVersionOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &CreateVersionOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateVersionOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*cxpb.Version, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp cxpb.Version + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateVersionOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*cxpb.Version, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp cxpb.Version + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateVersionOperation) Metadata() (*cxpb.CreateVersionOperationMetadata, error) { + var meta cxpb.CreateVersionOperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateVersionOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *CreateVersionOperation) Name() string { + return op.lro.Name() +} + +// LoadVersionOperation manages a long-running operation from LoadVersion. +type LoadVersionOperation struct { + lro *longrunning.Operation + pollPath string +} + +// LoadVersionOperation returns a new LoadVersionOperation from a given name. +// The name must be that of a previously created LoadVersionOperation, possibly from a different process. +func (c *versionsGRPCClient) LoadVersionOperation(name string) *LoadVersionOperation { + return &LoadVersionOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// LoadVersionOperation returns a new LoadVersionOperation from a given name. +// The name must be that of a previously created LoadVersionOperation, possibly from a different process. +func (c *versionsRESTClient) LoadVersionOperation(name string) *LoadVersionOperation { + override := fmt.Sprintf("/v3beta1/%s", name) + return &LoadVersionOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, } } @@ -809,6 +1769,7 @@ func (c *versionsGRPCClient) LoadVersionOperation(name string) *LoadVersionOpera // // See documentation of Poll for error-handling information. func (op *LoadVersionOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -822,6 +1783,7 @@ func (op *LoadVersionOperation) Wait(ctx context.Context, opts ...gax.CallOption // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *LoadVersionOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } diff --git a/dialogflow/cx/apiv3beta1/versions_client_example_test.go b/dialogflow/cx/apiv3beta1/versions_client_example_test.go index cff15722a9cf..22f1d3fb5de7 100644 --- a/dialogflow/cx/apiv3beta1/versions_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/versions_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewVersionsClient() { _ = c } +func ExampleNewVersionsRESTClient() { + ctx := context.Background() + c, err := cx.NewVersionsRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleVersionsClient_ListVersions() { ctx := context.Background() c, err := cx.NewVersionsClient(ctx) diff --git a/dialogflow/cx/apiv3beta1/webhooks_client.go b/dialogflow/cx/apiv3beta1/webhooks_client.go index 33b9906af914..ee735357c664 100644 --- a/dialogflow/cx/apiv3beta1/webhooks_client.go +++ b/dialogflow/cx/apiv3beta1/webhooks_client.go @@ -17,23 +17,29 @@ package cx import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" cxpb "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -130,6 +136,66 @@ func defaultWebhooksCallOptions() *WebhooksCallOptions { } } +func defaultWebhooksRESTCallOptions() *WebhooksCallOptions { + return &WebhooksCallOptions{ + ListWebhooks: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetWebhook: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateWebhook: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateWebhook: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteWebhook: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalWebhooksClient is an interface that defines the methods available from Dialogflow API. type internalWebhooksClient interface { Close() error @@ -317,6 +383,74 @@ func (c *webhooksGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type webhooksRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing WebhooksClient + CallOptions **WebhooksCallOptions +} + +// NewWebhooksRESTClient creates a new webhooks rest client. +// +// Service for managing Webhooks. +func NewWebhooksRESTClient(ctx context.Context, opts ...option.ClientOption) (*WebhooksClient, error) { + clientOpts := append(defaultWebhooksRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultWebhooksRESTCallOptions() + c := &webhooksRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &WebhooksClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultWebhooksRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://dialogflow.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://dialogflow.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://dialogflow.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *webhooksRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *webhooksRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *webhooksRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *webhooksGRPCClient) ListWebhooks(ctx context.Context, req *cxpb.ListWebhooksRequest, opts ...gax.CallOption) *WebhookIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -583,6 +717,636 @@ func (c *webhooksGRPCClient) ListOperations(ctx context.Context, req *longrunnin return it } +// ListWebhooks returns the list of all webhooks in the specified agent. +func (c *webhooksRESTClient) ListWebhooks(ctx context.Context, req *cxpb.ListWebhooksRequest, opts ...gax.CallOption) *WebhookIterator { + it := &WebhookIterator{} + req = proto.Clone(req).(*cxpb.ListWebhooksRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*cxpb.Webhook, string, error) { + resp := &cxpb.ListWebhooksResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/webhooks", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetWebhooks(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetWebhook retrieves the specified webhook. +func (c *webhooksRESTClient) GetWebhook(ctx context.Context, req *cxpb.GetWebhookRequest, opts ...gax.CallOption) (*cxpb.Webhook, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetWebhook[0:len((*c.CallOptions).GetWebhook):len((*c.CallOptions).GetWebhook)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Webhook{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateWebhook creates a webhook in the specified agent. +func (c *webhooksRESTClient) CreateWebhook(ctx context.Context, req *cxpb.CreateWebhookRequest, opts ...gax.CallOption) (*cxpb.Webhook, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetWebhook() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/webhooks", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateWebhook[0:len((*c.CallOptions).CreateWebhook):len((*c.CallOptions).CreateWebhook)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Webhook{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateWebhook updates the specified webhook. +func (c *webhooksRESTClient) UpdateWebhook(ctx context.Context, req *cxpb.UpdateWebhookRequest, opts ...gax.CallOption) (*cxpb.Webhook, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetWebhook() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetWebhook().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "webhook.name", url.QueryEscape(req.GetWebhook().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateWebhook[0:len((*c.CallOptions).UpdateWebhook):len((*c.CallOptions).UpdateWebhook)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &cxpb.Webhook{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteWebhook deletes the specified webhook. +func (c *webhooksRESTClient) DeleteWebhook(ctx context.Context, req *cxpb.DeleteWebhookRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetForce() { + params.Add("force", fmt.Sprintf("%v", req.GetForce())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetLocation gets information about a location. +func (c *webhooksRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *webhooksRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *webhooksRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *webhooksRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *webhooksRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v3beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // WebhookIterator manages a stream of *cxpb.Webhook. type WebhookIterator struct { items []*cxpb.Webhook diff --git a/dialogflow/cx/apiv3beta1/webhooks_client_example_test.go b/dialogflow/cx/apiv3beta1/webhooks_client_example_test.go index 6c2057c8cfff..276f71031fe6 100644 --- a/dialogflow/cx/apiv3beta1/webhooks_client_example_test.go +++ b/dialogflow/cx/apiv3beta1/webhooks_client_example_test.go @@ -38,6 +38,18 @@ func ExampleNewWebhooksClient() { _ = c } +func ExampleNewWebhooksRESTClient() { + ctx := context.Background() + c, err := cx.NewWebhooksRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleWebhooksClient_ListWebhooks() { ctx := context.Background() c, err := cx.NewWebhooksClient(ctx) diff --git a/domains/apiv1beta1/doc.go b/domains/apiv1beta1/doc.go index 273341b78fd3..cee913b37873 100644 --- a/domains/apiv1beta1/doc.go +++ b/domains/apiv1beta1/doc.go @@ -71,6 +71,8 @@ package domains // import "cloud.google.com/go/domains/apiv1beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -159,3 +161,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/domains/apiv1beta1/domains_client.go b/domains/apiv1beta1/domains_client.go index 6c72294fae8d..ee7e0d80d209 100644 --- a/domains/apiv1beta1/domains_client.go +++ b/domains/apiv1beta1/domains_client.go @@ -17,23 +17,29 @@ package domains import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" domainspb "google.golang.org/genproto/googleapis/cloud/domains/v1beta1" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -90,6 +96,26 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + SearchDomains: []gax.CallOption{}, + RetrieveRegisterParameters: []gax.CallOption{}, + RegisterDomain: []gax.CallOption{}, + RetrieveTransferParameters: []gax.CallOption{}, + TransferDomain: []gax.CallOption{}, + ListRegistrations: []gax.CallOption{}, + GetRegistration: []gax.CallOption{}, + UpdateRegistration: []gax.CallOption{}, + ConfigureManagementSettings: []gax.CallOption{}, + ConfigureDnsSettings: []gax.CallOption{}, + ConfigureContactSettings: []gax.CallOption{}, + ExportRegistration: []gax.CallOption{}, + DeleteRegistration: []gax.CallOption{}, + RetrieveAuthorizationCode: []gax.CallOption{}, + ResetAuthorizationCode: []gax.CallOption{}, + } +} + // internalClient is an interface that defines the methods available from Cloud Domains API. type internalClient interface { Close() error @@ -461,6 +487,89 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new domains rest client. +// +// The Cloud Domains API enables management and configuration of domain names. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://domains.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://domains.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://domains.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) SearchDomains(ctx context.Context, req *domainspb.SearchDomainsRequest, opts ...gax.CallOption) (*domainspb.SearchDomainsResponse, error) { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "location", url.QueryEscape(req.GetLocation()))) @@ -760,148 +869,1193 @@ func (c *gRPCClient) ResetAuthorizationCode(ctx context.Context, req *domainspb. return resp, nil } -// ConfigureContactSettingsOperation manages a long-running operation from ConfigureContactSettings. -type ConfigureContactSettingsOperation struct { - lro *longrunning.Operation -} - -// ConfigureContactSettingsOperation returns a new ConfigureContactSettingsOperation from a given name. -// The name must be that of a previously created ConfigureContactSettingsOperation, possibly from a different process. -func (c *gRPCClient) ConfigureContactSettingsOperation(name string) *ConfigureContactSettingsOperation { - return &ConfigureContactSettingsOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), - } -} - -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// SearchDomains searches for available domain names similar to the provided query. // -// See documentation of Poll for error-handling information. -func (op *ConfigureContactSettingsOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { - var resp domainspb.Registration - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { +// Availability results from this method are approximate; call +// RetrieveRegisterParameters on a domain before registering to confirm +// availability. +func (c *restClient) SearchDomains(ctx context.Context, req *domainspb.SearchDomainsRequest, opts ...gax.CallOption) (*domainspb.SearchDomainsResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - return &resp, nil -} + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/registrations:searchDomains", req.GetLocation()) -// Poll fetches the latest state of the long-running operation. -// -// Poll also fetches the latest metadata, which can be retrieved by Metadata. -// -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *ConfigureContactSettingsOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { - var resp domainspb.Registration - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { - return nil, err - } - if !op.Done() { - return nil, nil + params := url.Values{} + params.Add("query", fmt.Sprintf("%v", req.GetQuery())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "location", url.QueryEscape(req.GetLocation()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SearchDomains[0:len((*c.CallOptions).SearchDomains):len((*c.CallOptions).SearchDomains)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &domainspb.SearchDomainsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e } - return &resp, nil + return resp, nil } -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. -// If the metadata is not available, the returned metadata and error are both nil. -func (op *ConfigureContactSettingsOperation) Metadata() (*domainspb.OperationMetadata, error) { - var meta domainspb.OperationMetadata - if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { - return nil, nil - } else if err != nil { +// RetrieveRegisterParameters gets parameters needed to register a new domain name, including price and +// up-to-date availability. Use the returned values to call RegisterDomain. +func (c *restClient) RetrieveRegisterParameters(ctx context.Context, req *domainspb.RetrieveRegisterParametersRequest, opts ...gax.CallOption) (*domainspb.RetrieveRegisterParametersResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - return &meta, nil -} + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/registrations:retrieveRegisterParameters", req.GetLocation()) -// Done reports whether the long-running operation has completed. -func (op *ConfigureContactSettingsOperation) Done() bool { - return op.lro.Done() -} + params := url.Values{} + params.Add("domainName", fmt.Sprintf("%v", req.GetDomainName())) -// Name returns the name of the long-running operation. -// The name is assigned by the server and is unique within the service from which the operation is created. -func (op *ConfigureContactSettingsOperation) Name() string { - return op.lro.Name() -} + baseUrl.RawQuery = params.Encode() -// ConfigureDnsSettingsOperation manages a long-running operation from ConfigureDnsSettings. -type ConfigureDnsSettingsOperation struct { - lro *longrunning.Operation -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "location", url.QueryEscape(req.GetLocation()))) -// ConfigureDnsSettingsOperation returns a new ConfigureDnsSettingsOperation from a given name. -// The name must be that of a previously created ConfigureDnsSettingsOperation, possibly from a different process. -func (c *gRPCClient) ConfigureDnsSettingsOperation(name string) *ConfigureDnsSettingsOperation { - return &ConfigureDnsSettingsOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), - } -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).RetrieveRegisterParameters[0:len((*c.CallOptions).RetrieveRegisterParameters):len((*c.CallOptions).RetrieveRegisterParameters)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &domainspb.RetrieveRegisterParametersResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. -// -// See documentation of Poll for error-handling information. -func (op *ConfigureDnsSettingsOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { - var resp domainspb.Registration - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { - return nil, err + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e } - return &resp, nil + return resp, nil } -// Poll fetches the latest state of the long-running operation. +// RegisterDomain registers a new domain name and creates a corresponding Registration +// resource. // -// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// Call RetrieveRegisterParameters first to check availability of the domain +// name and determine parameters like price that are needed to build a call to +// this method. // -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *ConfigureDnsSettingsOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { - var resp domainspb.Registration - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { +// A successful call creates a Registration resource in state +// REGISTRATION_PENDING, which resolves to ACTIVE within 1-2 +// minutes, indicating that the domain was successfully registered. If the +// resource ends up in state REGISTRATION_FAILED, it indicates that the +// domain was not registered successfully, and you can safely delete the +// resource and retry registration. +func (c *restClient) RegisterDomain(ctx context.Context, req *domainspb.RegisterDomainRequest, opts ...gax.CallOption) (*RegisterDomainOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { return nil, err } - if !op.Done() { - return nil, nil - } - return &resp, nil -} -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. -// If the metadata is not available, the returned metadata and error are both nil. -func (op *ConfigureDnsSettingsOperation) Metadata() (*domainspb.OperationMetadata, error) { - var meta domainspb.OperationMetadata - if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { - return nil, nil - } else if err != nil { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - return &meta, nil -} - -// Done reports whether the long-running operation has completed. -func (op *ConfigureDnsSettingsOperation) Done() bool { - return op.lro.Done() -} + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/registrations:register", req.GetParent()) -// Name returns the name of the long-running operation. -// The name is assigned by the server and is unique within the service from which the operation is created. -func (op *ConfigureDnsSettingsOperation) Name() string { - return op.lro.Name() -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) -// ConfigureManagementSettingsOperation manages a long-running operation from ConfigureManagementSettings. -type ConfigureManagementSettingsOperation struct { - lro *longrunning.Operation -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &RegisterDomainOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// RetrieveTransferParameters gets parameters needed to transfer a domain name from another registrar to +// Cloud Domains. For domains managed by Google Domains, transferring to Cloud +// Domains is not supported. +// +// Use the returned values to call TransferDomain. +func (c *restClient) RetrieveTransferParameters(ctx context.Context, req *domainspb.RetrieveTransferParametersRequest, opts ...gax.CallOption) (*domainspb.RetrieveTransferParametersResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/registrations:retrieveTransferParameters", req.GetLocation()) + + params := url.Values{} + params.Add("domainName", fmt.Sprintf("%v", req.GetDomainName())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "location", url.QueryEscape(req.GetLocation()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).RetrieveTransferParameters[0:len((*c.CallOptions).RetrieveTransferParameters):len((*c.CallOptions).RetrieveTransferParameters)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &domainspb.RetrieveTransferParametersResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// TransferDomain transfers a domain name from another registrar to Cloud Domains. For +// domains managed by Google Domains, transferring to Cloud Domains is not +// supported. +// +// Before calling this method, go to the domain’s current registrar to unlock +// the domain for transfer and retrieve the domain’s transfer authorization +// code. Then call RetrieveTransferParameters to confirm that the domain is +// unlocked and to get values needed to build a call to this method. +// +// A successful call creates a Registration resource in state +// TRANSFER_PENDING. It can take several days to complete the transfer +// process. The registrant can often speed up this process by approving the +// transfer through the current registrar, either by clicking a link in an +// email from the registrar or by visiting the registrar’s website. +// +// A few minutes after transfer approval, the resource transitions to state +// ACTIVE, indicating that the transfer was successful. If the transfer is +// rejected or the request expires without being approved, the resource can +// end up in state TRANSFER_FAILED. If transfer fails, you can safely delete +// the resource and retry the transfer. +func (c *restClient) TransferDomain(ctx context.Context, req *domainspb.TransferDomainRequest, opts ...gax.CallOption) (*TransferDomainOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/registrations:transfer", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &TransferDomainOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ListRegistrations lists the Registration resources in a project. +func (c *restClient) ListRegistrations(ctx context.Context, req *domainspb.ListRegistrationsRequest, opts ...gax.CallOption) *RegistrationIterator { + it := &RegistrationIterator{} + req = proto.Clone(req).(*domainspb.ListRegistrationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*domainspb.Registration, string, error) { + resp := &domainspb.ListRegistrationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/registrations", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetRegistrations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetRegistration gets the details of a Registration resource. +func (c *restClient) GetRegistration(ctx context.Context, req *domainspb.GetRegistrationRequest, opts ...gax.CallOption) (*domainspb.Registration, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetRegistration[0:len((*c.CallOptions).GetRegistration):len((*c.CallOptions).GetRegistration)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &domainspb.Registration{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateRegistration updates select fields of a Registration resource, notably labels. To +// update other fields, use the appropriate custom update method: +// +// To update management settings, see ConfigureManagementSettings +// +// To update DNS configuration, see ConfigureDnsSettings +// +// To update contact information, see ConfigureContactSettings +func (c *restClient) UpdateRegistration(ctx context.Context, req *domainspb.UpdateRegistrationRequest, opts ...gax.CallOption) (*UpdateRegistrationOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetRegistration() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetRegistration().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "registration.name", url.QueryEscape(req.GetRegistration().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &UpdateRegistrationOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ConfigureManagementSettings updates a Registration's management settings. +func (c *restClient) ConfigureManagementSettings(ctx context.Context, req *domainspb.ConfigureManagementSettingsRequest, opts ...gax.CallOption) (*ConfigureManagementSettingsOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:configureManagementSettings", req.GetRegistration()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "registration", url.QueryEscape(req.GetRegistration()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &ConfigureManagementSettingsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ConfigureDnsSettings updates a Registration's DNS settings. +func (c *restClient) ConfigureDnsSettings(ctx context.Context, req *domainspb.ConfigureDnsSettingsRequest, opts ...gax.CallOption) (*ConfigureDnsSettingsOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:configureDnsSettings", req.GetRegistration()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "registration", url.QueryEscape(req.GetRegistration()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &ConfigureDnsSettingsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ConfigureContactSettings updates a Registration's contact settings. Some changes require +// confirmation by the domain’s registrant contact . +func (c *restClient) ConfigureContactSettings(ctx context.Context, req *domainspb.ConfigureContactSettingsRequest, opts ...gax.CallOption) (*ConfigureContactSettingsOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:configureContactSettings", req.GetRegistration()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "registration", url.QueryEscape(req.GetRegistration()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &ConfigureContactSettingsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ExportRegistration exports a Registration resource, such that it is no longer managed by +// Cloud Domains. +// +// When an active domain is successfully exported, you can continue to use the +// domain in Google Domains (at https://domains.google/) until it expires. The +// calling user becomes the domain’s sole owner in Google Domains, and +// permissions for the domain are subsequently managed there. The domain does +// not renew automatically unless the new owner sets up billing in Google +// Domains. +func (c *restClient) ExportRegistration(ctx context.Context, req *domainspb.ExportRegistrationRequest, opts ...gax.CallOption) (*ExportRegistrationOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:export", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &ExportRegistrationOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// DeleteRegistration deletes a Registration resource. +// +// This method works on any Registration resource using Subscription or +// Commitment billing (at /domains/pricing#billing-models), provided that the +// resource was created at least 1 day in the past. +// +// For Registration resources using +// Monthly billing (at /domains/pricing#billing-models), this method works if: +// +// state is EXPORTED with expire_time in the past +// +// state is REGISTRATION_FAILED +// +// state is TRANSFER_FAILED +// +// When an active registration is successfully deleted, you can continue to +// use the domain in Google Domains (at https://domains.google/) until it +// expires. The calling user becomes the domain’s sole owner in Google +// Domains, and permissions for the domain are subsequently managed there. The +// domain does not renew automatically unless the new owner sets up billing in +// Google Domains. +func (c *restClient) DeleteRegistration(ctx context.Context, req *domainspb.DeleteRegistrationRequest, opts ...gax.CallOption) (*DeleteRegistrationOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &DeleteRegistrationOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// RetrieveAuthorizationCode gets the authorization code of the Registration for the purpose of +// transferring the domain to another registrar. +// +// You can call this method only after 60 days have elapsed since the initial +// domain registration. +func (c *restClient) RetrieveAuthorizationCode(ctx context.Context, req *domainspb.RetrieveAuthorizationCodeRequest, opts ...gax.CallOption) (*domainspb.AuthorizationCode, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:retrieveAuthorizationCode", req.GetRegistration()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "registration", url.QueryEscape(req.GetRegistration()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).RetrieveAuthorizationCode[0:len((*c.CallOptions).RetrieveAuthorizationCode):len((*c.CallOptions).RetrieveAuthorizationCode)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &domainspb.AuthorizationCode{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ResetAuthorizationCode resets the authorization code of the Registration to a new random string. +// +// You can call this method only after 60 days have elapsed since the initial +// domain registration. +func (c *restClient) ResetAuthorizationCode(ctx context.Context, req *domainspb.ResetAuthorizationCodeRequest, opts ...gax.CallOption) (*domainspb.AuthorizationCode, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:resetAuthorizationCode", req.GetRegistration()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "registration", url.QueryEscape(req.GetRegistration()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ResetAuthorizationCode[0:len((*c.CallOptions).ResetAuthorizationCode):len((*c.CallOptions).ResetAuthorizationCode)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &domainspb.AuthorizationCode{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ConfigureContactSettingsOperation manages a long-running operation from ConfigureContactSettings. +type ConfigureContactSettingsOperation struct { + lro *longrunning.Operation + pollPath string +} + +// ConfigureContactSettingsOperation returns a new ConfigureContactSettingsOperation from a given name. +// The name must be that of a previously created ConfigureContactSettingsOperation, possibly from a different process. +func (c *gRPCClient) ConfigureContactSettingsOperation(name string) *ConfigureContactSettingsOperation { + return &ConfigureContactSettingsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// ConfigureContactSettingsOperation returns a new ConfigureContactSettingsOperation from a given name. +// The name must be that of a previously created ConfigureContactSettingsOperation, possibly from a different process. +func (c *restClient) ConfigureContactSettingsOperation(name string) *ConfigureContactSettingsOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &ConfigureContactSettingsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *ConfigureContactSettingsOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp domainspb.Registration + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *ConfigureContactSettingsOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp domainspb.Registration + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *ConfigureContactSettingsOperation) Metadata() (*domainspb.OperationMetadata, error) { + var meta domainspb.OperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *ConfigureContactSettingsOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *ConfigureContactSettingsOperation) Name() string { + return op.lro.Name() +} + +// ConfigureDnsSettingsOperation manages a long-running operation from ConfigureDnsSettings. +type ConfigureDnsSettingsOperation struct { + lro *longrunning.Operation + pollPath string +} + +// ConfigureDnsSettingsOperation returns a new ConfigureDnsSettingsOperation from a given name. +// The name must be that of a previously created ConfigureDnsSettingsOperation, possibly from a different process. +func (c *gRPCClient) ConfigureDnsSettingsOperation(name string) *ConfigureDnsSettingsOperation { + return &ConfigureDnsSettingsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// ConfigureDnsSettingsOperation returns a new ConfigureDnsSettingsOperation from a given name. +// The name must be that of a previously created ConfigureDnsSettingsOperation, possibly from a different process. +func (c *restClient) ConfigureDnsSettingsOperation(name string) *ConfigureDnsSettingsOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &ConfigureDnsSettingsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *ConfigureDnsSettingsOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp domainspb.Registration + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *ConfigureDnsSettingsOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp domainspb.Registration + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *ConfigureDnsSettingsOperation) Metadata() (*domainspb.OperationMetadata, error) { + var meta domainspb.OperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *ConfigureDnsSettingsOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *ConfigureDnsSettingsOperation) Name() string { + return op.lro.Name() +} + +// ConfigureManagementSettingsOperation manages a long-running operation from ConfigureManagementSettings. +type ConfigureManagementSettingsOperation struct { + lro *longrunning.Operation + pollPath string +} // ConfigureManagementSettingsOperation returns a new ConfigureManagementSettingsOperation from a given name. // The name must be that of a previously created ConfigureManagementSettingsOperation, possibly from a different process. @@ -911,10 +2065,21 @@ func (c *gRPCClient) ConfigureManagementSettingsOperation(name string) *Configur } } +// ConfigureManagementSettingsOperation returns a new ConfigureManagementSettingsOperation from a given name. +// The name must be that of a previously created ConfigureManagementSettingsOperation, possibly from a different process. +func (c *restClient) ConfigureManagementSettingsOperation(name string) *ConfigureManagementSettingsOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &ConfigureManagementSettingsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *ConfigureManagementSettingsOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp domainspb.Registration if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -932,6 +2097,7 @@ func (op *ConfigureManagementSettingsOperation) Wait(ctx context.Context, opts . // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *ConfigureManagementSettingsOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp domainspb.Registration if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -969,7 +2135,8 @@ func (op *ConfigureManagementSettingsOperation) Name() string { // DeleteRegistrationOperation manages a long-running operation from DeleteRegistration. type DeleteRegistrationOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // DeleteRegistrationOperation returns a new DeleteRegistrationOperation from a given name. @@ -980,10 +2147,21 @@ func (c *gRPCClient) DeleteRegistrationOperation(name string) *DeleteRegistratio } } +// DeleteRegistrationOperation returns a new DeleteRegistrationOperation from a given name. +// The name must be that of a previously created DeleteRegistrationOperation, possibly from a different process. +func (c *restClient) DeleteRegistrationOperation(name string) *DeleteRegistrationOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &DeleteRegistrationOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *DeleteRegistrationOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -997,6 +2175,7 @@ func (op *DeleteRegistrationOperation) Wait(ctx context.Context, opts ...gax.Cal // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeleteRegistrationOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1027,7 +2206,8 @@ func (op *DeleteRegistrationOperation) Name() string { // ExportRegistrationOperation manages a long-running operation from ExportRegistration. type ExportRegistrationOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // ExportRegistrationOperation returns a new ExportRegistrationOperation from a given name. @@ -1038,10 +2218,21 @@ func (c *gRPCClient) ExportRegistrationOperation(name string) *ExportRegistratio } } +// ExportRegistrationOperation returns a new ExportRegistrationOperation from a given name. +// The name must be that of a previously created ExportRegistrationOperation, possibly from a different process. +func (c *restClient) ExportRegistrationOperation(name string) *ExportRegistrationOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &ExportRegistrationOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *ExportRegistrationOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp domainspb.Registration if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1059,6 +2250,7 @@ func (op *ExportRegistrationOperation) Wait(ctx context.Context, opts ...gax.Cal // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *ExportRegistrationOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp domainspb.Registration if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1096,7 +2288,8 @@ func (op *ExportRegistrationOperation) Name() string { // RegisterDomainOperation manages a long-running operation from RegisterDomain. type RegisterDomainOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // RegisterDomainOperation returns a new RegisterDomainOperation from a given name. @@ -1107,10 +2300,21 @@ func (c *gRPCClient) RegisterDomainOperation(name string) *RegisterDomainOperati } } +// RegisterDomainOperation returns a new RegisterDomainOperation from a given name. +// The name must be that of a previously created RegisterDomainOperation, possibly from a different process. +func (c *restClient) RegisterDomainOperation(name string) *RegisterDomainOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &RegisterDomainOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *RegisterDomainOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp domainspb.Registration if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1128,6 +2332,7 @@ func (op *RegisterDomainOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *RegisterDomainOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp domainspb.Registration if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1165,7 +2370,8 @@ func (op *RegisterDomainOperation) Name() string { // TransferDomainOperation manages a long-running operation from TransferDomain. type TransferDomainOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // TransferDomainOperation returns a new TransferDomainOperation from a given name. @@ -1176,10 +2382,21 @@ func (c *gRPCClient) TransferDomainOperation(name string) *TransferDomainOperati } } +// TransferDomainOperation returns a new TransferDomainOperation from a given name. +// The name must be that of a previously created TransferDomainOperation, possibly from a different process. +func (c *restClient) TransferDomainOperation(name string) *TransferDomainOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &TransferDomainOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *TransferDomainOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp domainspb.Registration if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1197,6 +2414,7 @@ func (op *TransferDomainOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *TransferDomainOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp domainspb.Registration if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1234,7 +2452,8 @@ func (op *TransferDomainOperation) Name() string { // UpdateRegistrationOperation manages a long-running operation from UpdateRegistration. type UpdateRegistrationOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UpdateRegistrationOperation returns a new UpdateRegistrationOperation from a given name. @@ -1245,10 +2464,21 @@ func (c *gRPCClient) UpdateRegistrationOperation(name string) *UpdateRegistratio } } +// UpdateRegistrationOperation returns a new UpdateRegistrationOperation from a given name. +// The name must be that of a previously created UpdateRegistrationOperation, possibly from a different process. +func (c *restClient) UpdateRegistrationOperation(name string) *UpdateRegistrationOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &UpdateRegistrationOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UpdateRegistrationOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp domainspb.Registration if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1266,6 +2496,7 @@ func (op *UpdateRegistrationOperation) Wait(ctx context.Context, opts ...gax.Cal // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UpdateRegistrationOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*domainspb.Registration, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp domainspb.Registration if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/domains/apiv1beta1/domains_client_example_test.go b/domains/apiv1beta1/domains_client_example_test.go index 683c5a200bfb..a785612a1933 100644 --- a/domains/apiv1beta1/domains_client_example_test.go +++ b/domains/apiv1beta1/domains_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := domains.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_SearchDomains() { ctx := context.Background() c, err := domains.NewClient(ctx) diff --git a/domains/apiv1beta1/gapic_metadata.json b/domains/apiv1beta1/gapic_metadata.json index 5fa7e3137567..7ea17efad964 100644 --- a/domains/apiv1beta1/gapic_metadata.json +++ b/domains/apiv1beta1/gapic_metadata.json @@ -86,6 +86,86 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "ConfigureContactSettings": { + "methods": [ + "ConfigureContactSettings" + ] + }, + "ConfigureDnsSettings": { + "methods": [ + "ConfigureDnsSettings" + ] + }, + "ConfigureManagementSettings": { + "methods": [ + "ConfigureManagementSettings" + ] + }, + "DeleteRegistration": { + "methods": [ + "DeleteRegistration" + ] + }, + "ExportRegistration": { + "methods": [ + "ExportRegistration" + ] + }, + "GetRegistration": { + "methods": [ + "GetRegistration" + ] + }, + "ListRegistrations": { + "methods": [ + "ListRegistrations" + ] + }, + "RegisterDomain": { + "methods": [ + "RegisterDomain" + ] + }, + "ResetAuthorizationCode": { + "methods": [ + "ResetAuthorizationCode" + ] + }, + "RetrieveAuthorizationCode": { + "methods": [ + "RetrieveAuthorizationCode" + ] + }, + "RetrieveRegisterParameters": { + "methods": [ + "RetrieveRegisterParameters" + ] + }, + "RetrieveTransferParameters": { + "methods": [ + "RetrieveTransferParameters" + ] + }, + "SearchDomains": { + "methods": [ + "SearchDomains" + ] + }, + "TransferDomain": { + "methods": [ + "TransferDomain" + ] + }, + "UpdateRegistration": { + "methods": [ + "UpdateRegistration" + ] + } + } } } } diff --git a/errorreporting/apiv1beta1/doc.go b/errorreporting/apiv1beta1/doc.go index 12ddc8d8d484..00e0176e3be2 100644 --- a/errorreporting/apiv1beta1/doc.go +++ b/errorreporting/apiv1beta1/doc.go @@ -73,6 +73,8 @@ package errorreporting // import "cloud.google.com/go/errorreporting/apiv1beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -161,3 +163,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/errorreporting/apiv1beta1/error_group_client.go b/errorreporting/apiv1beta1/error_group_client.go index 2ce5d0c5203c..d60f9ece2fbf 100644 --- a/errorreporting/apiv1beta1/error_group_client.go +++ b/errorreporting/apiv1beta1/error_group_client.go @@ -17,20 +17,26 @@ package errorreporting import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" clouderrorreportingpb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newErrorGroupClientHook clientHook @@ -82,6 +88,33 @@ func defaultErrorGroupCallOptions() *ErrorGroupCallOptions { } } +func defaultErrorGroupRESTCallOptions() *ErrorGroupCallOptions { + return &ErrorGroupCallOptions{ + GetGroup: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + UpdateGroup: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + } +} + // internalErrorGroupClient is an interface that defines the methods available from Error Reporting API. type internalErrorGroupClient interface { Close() error @@ -216,6 +249,74 @@ func (c *errorGroupGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type errorGroupRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing ErrorGroupClient + CallOptions **ErrorGroupCallOptions +} + +// NewErrorGroupRESTClient creates a new error group service rest client. +// +// Service for retrieving and updating individual error groups. +func NewErrorGroupRESTClient(ctx context.Context, opts ...option.ClientOption) (*ErrorGroupClient, error) { + clientOpts := append(defaultErrorGroupRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultErrorGroupRESTCallOptions() + c := &errorGroupRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &ErrorGroupClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultErrorGroupRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://clouderrorreporting.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://clouderrorreporting.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://clouderrorreporting.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *errorGroupRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *errorGroupRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *errorGroupRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *errorGroupGRPCClient) GetGroup(ctx context.Context, req *clouderrorreportingpb.GetGroupRequest, opts ...gax.CallOption) (*clouderrorreportingpb.ErrorGroup, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) @@ -259,3 +360,117 @@ func (c *errorGroupGRPCClient) UpdateGroup(ctx context.Context, req *clouderrorr } return resp, nil } + +// GetGroup get the specified group. +func (c *errorGroupRESTClient) GetGroup(ctx context.Context, req *clouderrorreportingpb.GetGroupRequest, opts ...gax.CallOption) (*clouderrorreportingpb.ErrorGroup, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetGroupName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "group_name", url.QueryEscape(req.GetGroupName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetGroup[0:len((*c.CallOptions).GetGroup):len((*c.CallOptions).GetGroup)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &clouderrorreportingpb.ErrorGroup{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateGroup replace the data for the specified group. +// Fails if the group does not exist. +func (c *errorGroupRESTClient) UpdateGroup(ctx context.Context, req *clouderrorreportingpb.UpdateGroupRequest, opts ...gax.CallOption) (*clouderrorreportingpb.ErrorGroup, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetGroup() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetGroup().GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "group.name", url.QueryEscape(req.GetGroup().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateGroup[0:len((*c.CallOptions).UpdateGroup):len((*c.CallOptions).UpdateGroup)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &clouderrorreportingpb.ErrorGroup{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PUT", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/errorreporting/apiv1beta1/error_group_client_example_test.go b/errorreporting/apiv1beta1/error_group_client_example_test.go index 0229fbd7051c..bcedbed8725c 100644 --- a/errorreporting/apiv1beta1/error_group_client_example_test.go +++ b/errorreporting/apiv1beta1/error_group_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewErrorGroupClient() { _ = c } +func ExampleNewErrorGroupRESTClient() { + ctx := context.Background() + c, err := errorreporting.NewErrorGroupRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleErrorGroupClient_GetGroup() { ctx := context.Background() c, err := errorreporting.NewErrorGroupClient(ctx) diff --git a/errorreporting/apiv1beta1/error_stats_client.go b/errorreporting/apiv1beta1/error_stats_client.go index e955ab38b8f4..640d3062303a 100644 --- a/errorreporting/apiv1beta1/error_stats_client.go +++ b/errorreporting/apiv1beta1/error_stats_client.go @@ -19,19 +19,24 @@ package errorreporting import ( "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" clouderrorreportingpb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -97,6 +102,44 @@ func defaultErrorStatsCallOptions() *ErrorStatsCallOptions { } } +func defaultErrorStatsRESTCallOptions() *ErrorStatsCallOptions { + return &ErrorStatsCallOptions{ + ListGroupStats: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + ListEvents: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + DeleteEvents: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + } +} + // internalErrorStatsClient is an interface that defines the methods available from Error Reporting API. type internalErrorStatsClient interface { Close() error @@ -238,6 +281,75 @@ func (c *errorStatsGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type errorStatsRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing ErrorStatsClient + CallOptions **ErrorStatsCallOptions +} + +// NewErrorStatsRESTClient creates a new error stats service rest client. +// +// An API for retrieving and managing error statistics as well as data for +// individual events. +func NewErrorStatsRESTClient(ctx context.Context, opts ...option.ClientOption) (*ErrorStatsClient, error) { + clientOpts := append(defaultErrorStatsRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultErrorStatsRESTCallOptions() + c := &errorStatsRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &ErrorStatsClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultErrorStatsRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://clouderrorreporting.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://clouderrorreporting.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://clouderrorreporting.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *errorStatsRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *errorStatsRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *errorStatsRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *errorStatsGRPCClient) ListGroupStats(ctx context.Context, req *clouderrorreportingpb.ListGroupStatsRequest, opts ...gax.CallOption) *ErrorGroupStatsIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "project_name", url.QueryEscape(req.GetProjectName()))) @@ -350,6 +462,279 @@ func (c *errorStatsGRPCClient) DeleteEvents(ctx context.Context, req *clouderror return resp, nil } +// ListGroupStats lists the specified groups. +func (c *errorStatsRESTClient) ListGroupStats(ctx context.Context, req *clouderrorreportingpb.ListGroupStatsRequest, opts ...gax.CallOption) *ErrorGroupStatsIterator { + it := &ErrorGroupStatsIterator{} + req = proto.Clone(req).(*clouderrorreportingpb.ListGroupStatsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*clouderrorreportingpb.ErrorGroupStats, string, error) { + resp := &clouderrorreportingpb.ListGroupStatsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/groupStats", req.GetProjectName()) + + params := url.Values{} + if req.GetAlignment() != 0 { + params.Add("alignment", fmt.Sprintf("%v", req.GetAlignment())) + } + if req.GetAlignmentTime().GetNanos() != 0 { + params.Add("alignmentTime.nanos", fmt.Sprintf("%v", req.GetAlignmentTime().GetNanos())) + } + if req.GetAlignmentTime().GetSeconds() != 0 { + params.Add("alignmentTime.seconds", fmt.Sprintf("%v", req.GetAlignmentTime().GetSeconds())) + } + if req.GetGroupId() != nil { + params.Add("groupId", fmt.Sprintf("%v", req.GetGroupId())) + } + if req.GetOrder() != 0 { + params.Add("order", fmt.Sprintf("%v", req.GetOrder())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetServiceFilter().GetResourceType() != "" { + params.Add("serviceFilter.resourceType", fmt.Sprintf("%v", req.GetServiceFilter().GetResourceType())) + } + if req.GetServiceFilter().GetService() != "" { + params.Add("serviceFilter.service", fmt.Sprintf("%v", req.GetServiceFilter().GetService())) + } + if req.GetServiceFilter().GetVersion() != "" { + params.Add("serviceFilter.version", fmt.Sprintf("%v", req.GetServiceFilter().GetVersion())) + } + if req.GetTimeRange().GetPeriod() != 0 { + params.Add("timeRange.period", fmt.Sprintf("%v", req.GetTimeRange().GetPeriod())) + } + if req.GetTimedCountDuration().GetNanos() != 0 { + params.Add("timedCountDuration.nanos", fmt.Sprintf("%v", req.GetTimedCountDuration().GetNanos())) + } + if req.GetTimedCountDuration().GetSeconds() != 0 { + params.Add("timedCountDuration.seconds", fmt.Sprintf("%v", req.GetTimedCountDuration().GetSeconds())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetErrorGroupStats(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// ListEvents lists the specified events. +func (c *errorStatsRESTClient) ListEvents(ctx context.Context, req *clouderrorreportingpb.ListEventsRequest, opts ...gax.CallOption) *ErrorEventIterator { + it := &ErrorEventIterator{} + req = proto.Clone(req).(*clouderrorreportingpb.ListEventsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*clouderrorreportingpb.ErrorEvent, string, error) { + resp := &clouderrorreportingpb.ListEventsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/events", req.GetProjectName()) + + params := url.Values{} + params.Add("groupId", fmt.Sprintf("%v", req.GetGroupId())) + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetServiceFilter().GetResourceType() != "" { + params.Add("serviceFilter.resourceType", fmt.Sprintf("%v", req.GetServiceFilter().GetResourceType())) + } + if req.GetServiceFilter().GetService() != "" { + params.Add("serviceFilter.service", fmt.Sprintf("%v", req.GetServiceFilter().GetService())) + } + if req.GetServiceFilter().GetVersion() != "" { + params.Add("serviceFilter.version", fmt.Sprintf("%v", req.GetServiceFilter().GetVersion())) + } + if req.GetTimeRange().GetPeriod() != 0 { + params.Add("timeRange.period", fmt.Sprintf("%v", req.GetTimeRange().GetPeriod())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetErrorEvents(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// DeleteEvents deletes all error events of a given project. +func (c *errorStatsRESTClient) DeleteEvents(ctx context.Context, req *clouderrorreportingpb.DeleteEventsRequest, opts ...gax.CallOption) (*clouderrorreportingpb.DeleteEventsResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/events", req.GetProjectName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "project_name", url.QueryEscape(req.GetProjectName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).DeleteEvents[0:len((*c.CallOptions).DeleteEvents):len((*c.CallOptions).DeleteEvents)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &clouderrorreportingpb.DeleteEventsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // ErrorEventIterator manages a stream of *clouderrorreportingpb.ErrorEvent. type ErrorEventIterator struct { items []*clouderrorreportingpb.ErrorEvent diff --git a/errorreporting/apiv1beta1/error_stats_client_example_test.go b/errorreporting/apiv1beta1/error_stats_client_example_test.go index ed22060e901e..72cbaff5ed2d 100644 --- a/errorreporting/apiv1beta1/error_stats_client_example_test.go +++ b/errorreporting/apiv1beta1/error_stats_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewErrorStatsClient() { _ = c } +func ExampleNewErrorStatsRESTClient() { + ctx := context.Background() + c, err := errorreporting.NewErrorStatsRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleErrorStatsClient_ListGroupStats() { ctx := context.Background() c, err := errorreporting.NewErrorStatsClient(ctx) diff --git a/errorreporting/apiv1beta1/gapic_metadata.json b/errorreporting/apiv1beta1/gapic_metadata.json index 8e6727a953a6..0c12e341a7ce 100644 --- a/errorreporting/apiv1beta1/gapic_metadata.json +++ b/errorreporting/apiv1beta1/gapic_metadata.json @@ -21,6 +21,21 @@ ] } } + }, + "rest": { + "libraryClient": "ErrorGroupClient", + "rpcs": { + "GetGroup": { + "methods": [ + "GetGroup" + ] + }, + "UpdateGroup": { + "methods": [ + "UpdateGroup" + ] + } + } } } }, @@ -45,6 +60,26 @@ ] } } + }, + "rest": { + "libraryClient": "ErrorStatsClient", + "rpcs": { + "DeleteEvents": { + "methods": [ + "DeleteEvents" + ] + }, + "ListEvents": { + "methods": [ + "ListEvents" + ] + }, + "ListGroupStats": { + "methods": [ + "ListGroupStats" + ] + } + } } } }, @@ -59,6 +94,16 @@ ] } } + }, + "rest": { + "libraryClient": "ReportErrorsClient", + "rpcs": { + "ReportErrorEvent": { + "methods": [ + "ReportErrorEvent" + ] + } + } } } } diff --git a/errorreporting/apiv1beta1/report_errors_client.go b/errorreporting/apiv1beta1/report_errors_client.go index 483d6163a236..bc088139dd21 100644 --- a/errorreporting/apiv1beta1/report_errors_client.go +++ b/errorreporting/apiv1beta1/report_errors_client.go @@ -17,19 +17,25 @@ package errorreporting import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" clouderrorreportingpb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newReportErrorsClientHook clientHook @@ -57,6 +63,12 @@ func defaultReportErrorsCallOptions() *ReportErrorsCallOptions { } } +func defaultReportErrorsRESTCallOptions() *ReportErrorsCallOptions { + return &ReportErrorsCallOptions{ + ReportErrorEvent: []gax.CallOption{}, + } +} + // internalReportErrorsClient is an interface that defines the methods available from Error Reporting API. type internalReportErrorsClient interface { Close() error @@ -199,6 +211,74 @@ func (c *reportErrorsGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type reportErrorsRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing ReportErrorsClient + CallOptions **ReportErrorsCallOptions +} + +// NewReportErrorsRESTClient creates a new report errors service rest client. +// +// An API for reporting error events. +func NewReportErrorsRESTClient(ctx context.Context, opts ...option.ClientOption) (*ReportErrorsClient, error) { + clientOpts := append(defaultReportErrorsRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultReportErrorsRESTCallOptions() + c := &reportErrorsRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &ReportErrorsClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultReportErrorsRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://clouderrorreporting.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://clouderrorreporting.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://clouderrorreporting.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *reportErrorsRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *reportErrorsRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *reportErrorsRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *reportErrorsGRPCClient) ReportErrorEvent(ctx context.Context, req *clouderrorreportingpb.ReportErrorEventRequest, opts ...gax.CallOption) (*clouderrorreportingpb.ReportErrorEventResponse, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) @@ -220,3 +300,78 @@ func (c *reportErrorsGRPCClient) ReportErrorEvent(ctx context.Context, req *clou } return resp, nil } + +// ReportErrorEvent report an individual error event and record the event to a log. +// +// This endpoint accepts either an OAuth token, +// or an API key (at https://support.google.com/cloud/answer/6158862) +// for authentication. To use an API key, append it to the URL as the value of +// a key parameter. For example: +// +// POST https://clouderrorreporting.googleapis.com/v1beta1/{projectName}/events:report?key=123ABC456 +// +// Note: Error Reporting (at /error-reporting) is a global service built +// on Cloud Logging and doesn’t analyze logs stored +// in regional log buckets or logs routed to other Google Cloud projects. +// +// For more information, see +// Using Error Reporting with regionalized +// logs (at /error-reporting/docs/regionalization). +func (c *reportErrorsRESTClient) ReportErrorEvent(ctx context.Context, req *clouderrorreportingpb.ReportErrorEventRequest, opts ...gax.CallOption) (*clouderrorreportingpb.ReportErrorEventResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetEvent() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/events:report", req.GetProjectName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "project_name", url.QueryEscape(req.GetProjectName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ReportErrorEvent[0:len((*c.CallOptions).ReportErrorEvent):len((*c.CallOptions).ReportErrorEvent)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &clouderrorreportingpb.ReportErrorEventResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/errorreporting/apiv1beta1/report_errors_client_example_test.go b/errorreporting/apiv1beta1/report_errors_client_example_test.go index c5e82ef22a04..42fae5602eae 100644 --- a/errorreporting/apiv1beta1/report_errors_client_example_test.go +++ b/errorreporting/apiv1beta1/report_errors_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewReportErrorsClient() { _ = c } +func ExampleNewReportErrorsRESTClient() { + ctx := context.Background() + c, err := errorreporting.NewReportErrorsRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleReportErrorsClient_ReportErrorEvent() { ctx := context.Background() c, err := errorreporting.NewReportErrorsClient(ctx) diff --git a/gkehub/apiv1beta1/doc.go b/gkehub/apiv1beta1/doc.go index 29d72b8a4511..490cd37d9097 100644 --- a/gkehub/apiv1beta1/doc.go +++ b/gkehub/apiv1beta1/doc.go @@ -75,6 +75,8 @@ package gkehub // import "cloud.google.com/go/gkehub/apiv1beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -163,3 +165,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/gkehub/apiv1beta1/gapic_metadata.json b/gkehub/apiv1beta1/gapic_metadata.json index f1a93e2a2ddc..216ada679361 100644 --- a/gkehub/apiv1beta1/gapic_metadata.json +++ b/gkehub/apiv1beta1/gapic_metadata.json @@ -96,6 +96,96 @@ ] } } + }, + "rest": { + "libraryClient": "GkeHubMembershipClient", + "rpcs": { + "CancelOperation": { + "methods": [ + "CancelOperation" + ] + }, + "CreateMembership": { + "methods": [ + "CreateMembership" + ] + }, + "DeleteMembership": { + "methods": [ + "DeleteMembership" + ] + }, + "DeleteOperation": { + "methods": [ + "DeleteOperation" + ] + }, + "GenerateConnectManifest": { + "methods": [ + "GenerateConnectManifest" + ] + }, + "GenerateExclusivityManifest": { + "methods": [ + "GenerateExclusivityManifest" + ] + }, + "GetIamPolicy": { + "methods": [ + "GetIamPolicy" + ] + }, + "GetLocation": { + "methods": [ + "GetLocation" + ] + }, + "GetMembership": { + "methods": [ + "GetMembership" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListLocations": { + "methods": [ + "ListLocations" + ] + }, + "ListMemberships": { + "methods": [ + "ListMemberships" + ] + }, + "ListOperations": { + "methods": [ + "ListOperations" + ] + }, + "SetIamPolicy": { + "methods": [ + "SetIamPolicy" + ] + }, + "TestIamPermissions": { + "methods": [ + "TestIamPermissions" + ] + }, + "UpdateMembership": { + "methods": [ + "UpdateMembership" + ] + }, + "ValidateExclusivity": { + "methods": [ + "ValidateExclusivity" + ] + } + } } } } diff --git a/gkehub/apiv1beta1/gke_hub_membership_client.go b/gkehub/apiv1beta1/gke_hub_membership_client.go index 7c2bae1f37af..662bb36f6a67 100644 --- a/gkehub/apiv1beta1/gke_hub_membership_client.go +++ b/gkehub/apiv1beta1/gke_hub_membership_client.go @@ -17,19 +17,24 @@ package gkehub import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" gkehubpb "google.golang.org/genproto/googleapis/cloud/gkehub/v1beta1" locationpb "google.golang.org/genproto/googleapis/cloud/location" iampb "google.golang.org/genproto/googleapis/iam/v1" @@ -37,6 +42,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -177,6 +183,100 @@ func defaultGkeHubMembershipCallOptions() *GkeHubMembershipCallOptions { } } +func defaultGkeHubMembershipRESTCallOptions() *GkeHubMembershipCallOptions { + return &GkeHubMembershipCallOptions{ + ListMemberships: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetMembership: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateMembership: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteMembership: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateMembership: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GenerateConnectManifest: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ValidateExclusivity: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GenerateExclusivityManifest: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetLocation: []gax.CallOption{}, + ListLocations: []gax.CallOption{}, + GetIamPolicy: []gax.CallOption{}, + SetIamPolicy: []gax.CallOption{}, + TestIamPermissions: []gax.CallOption{}, + CancelOperation: []gax.CallOption{}, + DeleteOperation: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + ListOperations: []gax.CallOption{}, + } +} + // internalGkeHubMembershipClient is an interface that defines the methods available from GKE Hub API. type internalGkeHubMembershipClient interface { Close() error @@ -499,6 +599,96 @@ func (c *gkeHubMembershipGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type gkeHubMembershipRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing GkeHubMembershipClient + CallOptions **GkeHubMembershipCallOptions +} + +// NewGkeHubMembershipRESTClient creates a new gke hub membership service rest client. +// +// The GKE Hub MembershipService handles the registration of many Kubernetes +// clusters to Google Cloud, represented with the Membership resource. +// +// GKE Hub is currently only available in the global region. +// +// Membership management may be non-trivial: it is recommended to use one +// of the Google-provided client libraries or tools where possible when working +// with Membership resources. +func NewGkeHubMembershipRESTClient(ctx context.Context, opts ...option.ClientOption) (*GkeHubMembershipClient, error) { + clientOpts := append(defaultGkeHubMembershipRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultGkeHubMembershipRESTCallOptions() + c := &gkeHubMembershipRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &GkeHubMembershipClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultGkeHubMembershipRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://gkehub.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://gkehub.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://gkehub.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *gkeHubMembershipRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *gkeHubMembershipRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *gkeHubMembershipRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *gkeHubMembershipGRPCClient) ListMemberships(ctx context.Context, req *gkehubpb.ListMembershipsRequest, opts ...gax.CallOption) *MembershipIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -905,93 +1095,1250 @@ func (c *gkeHubMembershipGRPCClient) ListOperations(ctx context.Context, req *lo return it } -// CreateMembershipOperation manages a long-running operation from CreateMembership. -type CreateMembershipOperation struct { - lro *longrunning.Operation -} +// ListMemberships lists Memberships in a given project and location. +func (c *gkeHubMembershipRESTClient) ListMemberships(ctx context.Context, req *gkehubpb.ListMembershipsRequest, opts ...gax.CallOption) *MembershipIterator { + it := &MembershipIterator{} + req = proto.Clone(req).(*gkehubpb.ListMembershipsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*gkehubpb.Membership, string, error) { + resp := &gkehubpb.ListMembershipsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/memberships", req.GetParent()) -// CreateMembershipOperation returns a new CreateMembershipOperation from a given name. -// The name must be that of a previously created CreateMembershipOperation, possibly from a different process. -func (c *gkeHubMembershipGRPCClient) CreateMembershipOperation(name string) *CreateMembershipOperation { - return &CreateMembershipOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), - } -} + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetOrderBy() != "" { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. -// -// See documentation of Poll for error-handling information. -func (op *CreateMembershipOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*gkehubpb.Membership, error) { - var resp gkehubpb.Membership - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { - return nil, err + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetResources(), resp.GetNextPageToken(), nil } - return &resp, nil -} -// Poll fetches the latest state of the long-running operation. -// -// Poll also fetches the latest metadata, which can be retrieved by Metadata. -// -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *CreateMembershipOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*gkehubpb.Membership, error) { - var resp gkehubpb.Membership - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { - return nil, err - } - if !op.Done() { - return nil, nil + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - return &resp, nil + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it } -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. -// If the metadata is not available, the returned metadata and error are both nil. -func (op *CreateMembershipOperation) Metadata() (*gkehubpb.OperationMetadata, error) { - var meta gkehubpb.OperationMetadata - if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { - return nil, nil - } else if err != nil { +// GetMembership gets the details of a Membership. +func (c *gkeHubMembershipRESTClient) GetMembership(ctx context.Context, req *gkehubpb.GetMembershipRequest, opts ...gax.CallOption) (*gkehubpb.Membership, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - return &meta, nil -} + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) -// Done reports whether the long-running operation has completed. -func (op *CreateMembershipOperation) Done() bool { - return op.lro.Done() -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) -// Name returns the name of the long-running operation. -// The name is assigned by the server and is unique within the service from which the operation is created. -func (op *CreateMembershipOperation) Name() string { - return op.lro.Name() -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetMembership[0:len((*c.CallOptions).GetMembership):len((*c.CallOptions).GetMembership)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &gkehubpb.Membership{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// DeleteMembershipOperation manages a long-running operation from DeleteMembership. -type DeleteMembershipOperation struct { - lro *longrunning.Operation -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// DeleteMembershipOperation returns a new DeleteMembershipOperation from a given name. -// The name must be that of a previously created DeleteMembershipOperation, possibly from a different process. -func (c *gkeHubMembershipGRPCClient) DeleteMembershipOperation(name string) *DeleteMembershipOperation { - return &DeleteMembershipOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e } + return resp, nil } -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// CreateMembership creates a new Membership. // -// See documentation of Poll for error-handling information. -func (op *DeleteMembershipOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { - return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) +// This is currently only supported for GKE clusters on Google Cloud. +// To register other clusters, follow the instructions at +// https://cloud.google.com/anthos/multicluster-management/connect/registering-a-cluster (at https://cloud.google.com/anthos/multicluster-management/connect/registering-a-cluster). +func (c *gkeHubMembershipRESTClient) CreateMembership(ctx context.Context, req *gkehubpb.CreateMembershipRequest, opts ...gax.CallOption) (*CreateMembershipOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetResource() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/memberships", req.GetParent()) + + params := url.Values{} + params.Add("membershipId", fmt.Sprintf("%v", req.GetMembershipId())) + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &CreateMembershipOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// DeleteMembership removes a Membership. +// +// This is currently only supported for GKE clusters on Google Cloud. +// To unregister other clusters, follow the instructions at +// https://cloud.google.com/anthos/multicluster-management/connect/unregistering-a-cluster (at https://cloud.google.com/anthos/multicluster-management/connect/unregistering-a-cluster). +func (c *gkeHubMembershipRESTClient) DeleteMembership(ctx context.Context, req *gkehubpb.DeleteMembershipRequest, opts ...gax.CallOption) (*DeleteMembershipOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &DeleteMembershipOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UpdateMembership updates an existing Membership. +func (c *gkeHubMembershipRESTClient) UpdateMembership(ctx context.Context, req *gkehubpb.UpdateMembershipRequest, opts ...gax.CallOption) (*UpdateMembershipOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetResource() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + params := url.Values{} + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &UpdateMembershipOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// GenerateConnectManifest generates the manifest for deployment of the GKE connect agent. +// +// This method is used internally by Google-provided libraries. +// Most clients should not need to call this method directly. +func (c *gkeHubMembershipRESTClient) GenerateConnectManifest(ctx context.Context, req *gkehubpb.GenerateConnectManifestRequest, opts ...gax.CallOption) (*gkehubpb.GenerateConnectManifestResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:generateConnectManifest", req.GetName()) + + params := url.Values{} + if req.GetConnectAgent().GetName() != "" { + params.Add("connectAgent.name", fmt.Sprintf("%v", req.GetConnectAgent().GetName())) + } + if req.GetConnectAgent().GetNamespace() != "" { + params.Add("connectAgent.namespace", fmt.Sprintf("%v", req.GetConnectAgent().GetNamespace())) + } + if req.GetConnectAgent().GetProxy() != nil { + params.Add("connectAgent.proxy", fmt.Sprintf("%v", req.GetConnectAgent().GetProxy())) + } + if req.GetImagePullSecretContent() != nil { + params.Add("imagePullSecretContent", fmt.Sprintf("%v", req.GetImagePullSecretContent())) + } + if req.GetIsUpgrade() { + params.Add("isUpgrade", fmt.Sprintf("%v", req.GetIsUpgrade())) + } + if req.GetRegistry() != "" { + params.Add("registry", fmt.Sprintf("%v", req.GetRegistry())) + } + if req.GetVersion() != "" { + params.Add("version", fmt.Sprintf("%v", req.GetVersion())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GenerateConnectManifest[0:len((*c.CallOptions).GenerateConnectManifest):len((*c.CallOptions).GenerateConnectManifest)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &gkehubpb.GenerateConnectManifestResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ValidateExclusivity validateExclusivity validates the state of exclusivity in the cluster. +// The validation does not depend on an existing Hub membership resource. +func (c *gkeHubMembershipRESTClient) ValidateExclusivity(ctx context.Context, req *gkehubpb.ValidateExclusivityRequest, opts ...gax.CallOption) (*gkehubpb.ValidateExclusivityResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/memberships:validateExclusivity", req.GetParent()) + + params := url.Values{} + if req.GetCrManifest() != "" { + params.Add("crManifest", fmt.Sprintf("%v", req.GetCrManifest())) + } + params.Add("intendedMembership", fmt.Sprintf("%v", req.GetIntendedMembership())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ValidateExclusivity[0:len((*c.CallOptions).ValidateExclusivity):len((*c.CallOptions).ValidateExclusivity)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &gkehubpb.ValidateExclusivityResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GenerateExclusivityManifest generateExclusivityManifest generates the manifests to update the +// exclusivity artifacts in the cluster if needed. +// +// Exclusivity artifacts include the Membership custom resource definition +// (CRD) and the singleton Membership custom resource (CR). Combined with +// ValidateExclusivity, exclusivity artifacts guarantee that a Kubernetes +// cluster is only registered to a single GKE Hub. +// +// The Membership CRD is versioned, and may require conversion when the GKE +// Hub API server begins serving a newer version of the CRD and +// corresponding CR. The response will be the converted CRD and CR if there +// are any differences between the versions. +func (c *gkeHubMembershipRESTClient) GenerateExclusivityManifest(ctx context.Context, req *gkehubpb.GenerateExclusivityManifestRequest, opts ...gax.CallOption) (*gkehubpb.GenerateExclusivityManifestResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:generateExclusivityManifest", req.GetName()) + + params := url.Values{} + if req.GetCrManifest() != "" { + params.Add("crManifest", fmt.Sprintf("%v", req.GetCrManifest())) + } + if req.GetCrdManifest() != "" { + params.Add("crdManifest", fmt.Sprintf("%v", req.GetCrdManifest())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GenerateExclusivityManifest[0:len((*c.CallOptions).GenerateExclusivityManifest):len((*c.CallOptions).GenerateExclusivityManifest)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &gkehubpb.GenerateExclusivityManifestResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetLocation gets information about a location. +func (c *gkeHubMembershipRESTClient) GetLocation(ctx context.Context, req *locationpb.GetLocationRequest, opts ...gax.CallOption) (*locationpb.Location, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLocation[0:len((*c.CallOptions).GetLocation):len((*c.CallOptions).GetLocation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &locationpb.Location{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListLocations lists information about the supported locations for this service. +func (c *gkeHubMembershipRESTClient) ListLocations(ctx context.Context, req *locationpb.ListLocationsRequest, opts ...gax.CallOption) *LocationIterator { + it := &LocationIterator{} + req = proto.Clone(req).(*locationpb.ListLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*locationpb.Location, string, error) { + resp := &locationpb.ListLocationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/locations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetLocations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetIamPolicy gets the access control policy for a resource. Returns an empty policy +// if the resource exists and does not have a policy set. +func (c *gkeHubMembershipRESTClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:getIamPolicy", req.GetResource()) + + params := url.Values{} + if req.GetOptions().GetRequestedPolicyVersion() != 0 { + params.Add("options.requestedPolicyVersion", fmt.Sprintf("%v", req.GetOptions().GetRequestedPolicyVersion())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetIamPolicy[0:len((*c.CallOptions).GetIamPolicy):len((*c.CallOptions).GetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// SetIamPolicy sets the access control policy on the specified resource. Replaces +// any existing policy. +// +// Can return NOT_FOUND, INVALID_ARGUMENT, and PERMISSION_DENIED +// errors. +func (c *gkeHubMembershipRESTClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:setIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SetIamPolicy[0:len((*c.CallOptions).SetIamPolicy):len((*c.CallOptions).SetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// TestIamPermissions returns permissions that a caller has on the specified resource. If the +// resource does not exist, this will return an empty set of +// permissions, not a NOT_FOUND error. +// +// Note: This operation is designed to be used for building +// permission-aware UIs and command-line tools, not for authorization +// checking. This operation may “fail open” without warning. +func (c *gkeHubMembershipRESTClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:testIamPermissions", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).TestIamPermissions[0:len((*c.CallOptions).TestIamPermissions):len((*c.CallOptions).TestIamPermissions)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.TestIamPermissionsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CancelOperation is a utility method from google.longrunning.Operations. +func (c *gkeHubMembershipRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// DeleteOperation is a utility method from google.longrunning.Operations. +func (c *gkeHubMembershipRESTClient) DeleteOperation(ctx context.Context, req *longrunningpb.DeleteOperationRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *gkeHubMembershipRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOperations is a utility method from google.longrunning.Operations. +func (c *gkeHubMembershipRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + resp := &longrunningpb.ListOperationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/operations", req.GetName()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOperations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CreateMembershipOperation manages a long-running operation from CreateMembership. +type CreateMembershipOperation struct { + lro *longrunning.Operation + pollPath string +} + +// CreateMembershipOperation returns a new CreateMembershipOperation from a given name. +// The name must be that of a previously created CreateMembershipOperation, possibly from a different process. +func (c *gkeHubMembershipGRPCClient) CreateMembershipOperation(name string) *CreateMembershipOperation { + return &CreateMembershipOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// CreateMembershipOperation returns a new CreateMembershipOperation from a given name. +// The name must be that of a previously created CreateMembershipOperation, possibly from a different process. +func (c *gkeHubMembershipRESTClient) CreateMembershipOperation(name string) *CreateMembershipOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &CreateMembershipOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateMembershipOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*gkehubpb.Membership, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp gkehubpb.Membership + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateMembershipOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*gkehubpb.Membership, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp gkehubpb.Membership + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateMembershipOperation) Metadata() (*gkehubpb.OperationMetadata, error) { + var meta gkehubpb.OperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateMembershipOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *CreateMembershipOperation) Name() string { + return op.lro.Name() +} + +// DeleteMembershipOperation manages a long-running operation from DeleteMembership. +type DeleteMembershipOperation struct { + lro *longrunning.Operation + pollPath string +} + +// DeleteMembershipOperation returns a new DeleteMembershipOperation from a given name. +// The name must be that of a previously created DeleteMembershipOperation, possibly from a different process. +func (c *gkeHubMembershipGRPCClient) DeleteMembershipOperation(name string) *DeleteMembershipOperation { + return &DeleteMembershipOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// DeleteMembershipOperation returns a new DeleteMembershipOperation from a given name. +// The name must be that of a previously created DeleteMembershipOperation, possibly from a different process. +func (c *gkeHubMembershipRESTClient) DeleteMembershipOperation(name string) *DeleteMembershipOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &DeleteMembershipOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *DeleteMembershipOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } // Poll fetches the latest state of the long-running operation. @@ -1004,6 +2351,7 @@ func (op *DeleteMembershipOperation) Wait(ctx context.Context, opts ...gax.CallO // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeleteMembershipOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1034,7 +2382,8 @@ func (op *DeleteMembershipOperation) Name() string { // UpdateMembershipOperation manages a long-running operation from UpdateMembership. type UpdateMembershipOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UpdateMembershipOperation returns a new UpdateMembershipOperation from a given name. @@ -1045,10 +2394,21 @@ func (c *gkeHubMembershipGRPCClient) UpdateMembershipOperation(name string) *Upd } } +// UpdateMembershipOperation returns a new UpdateMembershipOperation from a given name. +// The name must be that of a previously created UpdateMembershipOperation, possibly from a different process. +func (c *gkeHubMembershipRESTClient) UpdateMembershipOperation(name string) *UpdateMembershipOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &UpdateMembershipOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UpdateMembershipOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*gkehubpb.Membership, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp gkehubpb.Membership if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1066,6 +2426,7 @@ func (op *UpdateMembershipOperation) Wait(ctx context.Context, opts ...gax.CallO // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UpdateMembershipOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*gkehubpb.Membership, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp gkehubpb.Membership if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/gkehub/apiv1beta1/gke_hub_membership_client_example_test.go b/gkehub/apiv1beta1/gke_hub_membership_client_example_test.go index e8fb322319bb..e9f6a1abc2d1 100644 --- a/gkehub/apiv1beta1/gke_hub_membership_client_example_test.go +++ b/gkehub/apiv1beta1/gke_hub_membership_client_example_test.go @@ -39,6 +39,18 @@ func ExampleNewGkeHubMembershipClient() { _ = c } +func ExampleNewGkeHubMembershipRESTClient() { + ctx := context.Background() + c, err := gkehub.NewGkeHubMembershipRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleGkeHubMembershipClient_ListMemberships() { ctx := context.Background() c, err := gkehub.NewGkeHubMembershipClient(ctx) diff --git a/internal/gapicgen/generator/config.go b/internal/gapicgen/generator/config.go index 296c0996db72..f69bc256f689 100644 --- a/internal/gapicgen/generator/config.go +++ b/internal/gapicgen/generator/config.go @@ -106,6 +106,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/language/apiv1beta2", GRPCServiceConfigPath: "language_grpc_service_config.json", ApiServiceConfigPath: "language_v1beta2.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -122,6 +123,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/memcache/apiv1beta2", GRPCServiceConfigPath: "memcache_grpc_service_config.json", ApiServiceConfigPath: "memcache_v1beta2.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -130,6 +132,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/phishingprotection/apiv1beta1", GRPCServiceConfigPath: "phishingprotection_grpc_service_config.json", ApiServiceConfigPath: "phishingprotection_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -154,6 +157,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/scheduler/apiv1beta1", GRPCServiceConfigPath: "cloudscheduler_grpc_service_config.json", ApiServiceConfigPath: "cloudscheduler_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -170,6 +174,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/speech/apiv1p1beta1", GRPCServiceConfigPath: "speech_grpc_service_config.json", ApiServiceConfigPath: "speech_v1p1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -178,6 +183,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/bigquery/connection/apiv1beta1", GRPCServiceConfigPath: "bigqueryconnection_grpc_service_config.json", ApiServiceConfigPath: "bigqueryconnection_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -194,6 +200,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/bigquery/dataexchange/apiv1beta1", GRPCServiceConfigPath: "analyticshub_grpc_service_config.json", ApiServiceConfigPath: "analyticshub_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -242,6 +249,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/bigquery/storage/apiv1beta1", GRPCServiceConfigPath: "bigquerystorage_grpc_service_config.json", ApiServiceConfigPath: "bigquerystorage_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -250,6 +258,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/bigquery/storage/apiv1beta2", GRPCServiceConfigPath: "bigquerystorage_grpc_service_config.json", ApiServiceConfigPath: "bigquerystorage_v1beta2.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -274,6 +283,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/recommender/apiv1beta1", GRPCServiceConfigPath: "recommender_grpc_service_config.json", ApiServiceConfigPath: "recommender_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -290,6 +300,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/cloudtasks/apiv2beta2", GRPCServiceConfigPath: "cloudtasks_grpc_service_config.json", ApiServiceConfigPath: "cloudtasks_v2beta2.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -298,6 +309,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/cloudtasks/apiv2beta3", GRPCServiceConfigPath: "cloudtasks_grpc_service_config.json", ApiServiceConfigPath: "cloudtasks_v2beta3.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -330,6 +342,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/webrisk/apiv1beta1", GRPCServiceConfigPath: "webrisk_grpc_service_config.json", ApiServiceConfigPath: "webrisk_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -346,6 +359,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/secretmanager/apiv1beta1", GRPCServiceConfigPath: "secretmanager_grpc_service_config.json", ApiServiceConfigPath: "secretmanager_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -362,6 +376,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/osconfig/apiv1alpha", GRPCServiceConfigPath: "osconfig_grpc_service_config.json", ApiServiceConfigPath: "osconfig_v1alpha.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "alpha", }, { @@ -370,6 +385,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/osconfig/apiv1beta", GRPCServiceConfigPath: "osconfig_grpc_service_config.json", ApiServiceConfigPath: "osconfig_v1beta.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -386,6 +402,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/osconfig/agentendpoint/apiv1beta", GRPCServiceConfigPath: "agentendpoint_grpc_service_config.json", ApiServiceConfigPath: "osconfig_v1beta.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -434,6 +451,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/oslogin/apiv1beta", GRPCServiceConfigPath: "oslogin_grpc_service_config.json", ApiServiceConfigPath: "oslogin_v1beta.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -450,6 +468,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/recaptchaenterprise/apiv1beta1", GRPCServiceConfigPath: "recaptchaenterprise_grpc_service_config.json", ApiServiceConfigPath: "recaptchaenterprise_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -466,6 +485,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/redis/apiv1beta1", GRPCServiceConfigPath: "redis_grpc_service_config.json", ApiServiceConfigPath: "redis_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -482,6 +502,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/errorreporting/apiv1beta1", GRPCServiceConfigPath: "errorreporting_grpc_service_config.json", ApiServiceConfigPath: "clouderrorreporting_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -602,6 +623,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/dialogflow/cx/apiv3beta1", GRPCServiceConfigPath: "dialogflow_grpc_service_config.json", ApiServiceConfigPath: "dialogflow_v3beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -643,6 +665,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/containeranalysis/apiv1beta1", GRPCServiceConfigPath: "containeranalysis_grpc_service_config.json", ApiServiceConfigPath: "containeranalysis_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -653,6 +676,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/containeranalysis/apiv1beta1", GRPCServiceConfigPath: "../containeranalysis_grpc_service_config.json", ApiServiceConfigPath: "../containeranalysis_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -669,6 +693,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/videointelligence/apiv1beta2", GRPCServiceConfigPath: "videointelligence_grpc_service_config.json", ApiServiceConfigPath: "../videointelligence_v1beta2.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -677,6 +702,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/asset/apiv1p2beta1", GRPCServiceConfigPath: "cloudasset_grpc_service_config.json", ApiServiceConfigPath: "cloudasset_v1p2beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -685,6 +711,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/asset/apiv1p5beta1", GRPCServiceConfigPath: "cloudasset_grpc_service_config.json", ApiServiceConfigPath: "cloudasset_v1p5beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -701,6 +728,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/vision/apiv1p1beta1", GRPCServiceConfigPath: "vision_grpc_service_config.json", ApiServiceConfigPath: "vision_v1p1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -725,6 +753,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/talent/apiv4beta1", GRPCServiceConfigPath: "talent_grpc_service_config.json", ApiServiceConfigPath: "jobs_v4beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -757,6 +786,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/automl/apiv1beta1", GRPCServiceConfigPath: "automl_grpc_service_config.json", ApiServiceConfigPath: "automl_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -781,6 +811,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/servicedirectory/apiv1beta1", GRPCServiceConfigPath: "servicedirectory_grpc_service_config.json", ApiServiceConfigPath: "servicedirectory_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -797,6 +828,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/gaming/apiv1beta", GRPCServiceConfigPath: "gaming_grpc_service_config.json", ApiServiceConfigPath: "gameservices_v1beta.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -877,6 +909,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/workflows/apiv1beta", GRPCServiceConfigPath: "workflows_grpc_service_config.json", ApiServiceConfigPath: "workflows_v1beta.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -893,6 +926,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/workflows/executions/apiv1beta", GRPCServiceConfigPath: "executions_grpc_service_config.json", ApiServiceConfigPath: "workflowexecutions_v1beta.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -901,6 +935,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/security/privateca/apiv1beta1", GRPCServiceConfigPath: "privateca_grpc_service_config.json", ApiServiceConfigPath: "privateca_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -917,6 +952,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/assuredworkloads/apiv1beta1", GRPCServiceConfigPath: "assuredworkloads_grpc_service_config.json", ApiServiceConfigPath: "assuredworkloads.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -972,6 +1008,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/binaryauthorization/apiv1beta1", GRPCServiceConfigPath: "binaryauthorization_grpc_service_config.json", ApiServiceConfigPath: "binaryauthorization_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -1012,6 +1049,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/dataqna/apiv1alpha", GRPCServiceConfigPath: "dataqna_grpc_service_config.json", ApiServiceConfigPath: "dataqna_v1alpha.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "alpha", }, { @@ -1044,6 +1082,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/domains/apiv1beta1", GRPCServiceConfigPath: "domains_grpc_service_config.json", ApiServiceConfigPath: "domains_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -1084,6 +1123,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/gkehub/apiv1beta1", GRPCServiceConfigPath: "membership_grpc_service_config.json", ApiServiceConfigPath: "gkehub_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -1116,6 +1156,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/metastore/apiv1beta", GRPCServiceConfigPath: "metastore_grpc_service_config.json", ApiServiceConfigPath: "metastore_v1beta.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -1172,6 +1213,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/privatecatalog/apiv1beta1", GRPCServiceConfigPath: "cloudprivatecatalog_grpc_service_config.json", ApiServiceConfigPath: "cloudprivatecatalog_v1beta1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -1196,6 +1238,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/lifesciences/apiv2beta", GRPCServiceConfigPath: "lifesciences_grpc_service_config.json", ApiServiceConfigPath: "lifesciences_v2beta.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -1228,6 +1271,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/datastream/apiv1alpha1", GRPCServiceConfigPath: "datastream_grpc_service_config.json", ApiServiceConfigPath: "datastream_v1alpha1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "alpha", }, { @@ -1236,6 +1280,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/dataflow/apiv1beta3", GRPCServiceConfigPath: "dataflow_grpc_service_config.json", ApiServiceConfigPath: "dataflow_v1beta3.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "beta", }, { @@ -1520,6 +1565,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/analytics/admin/apiv1alpha", GRPCServiceConfigPath: "admin_grpc_service_config.json", ApiServiceConfigPath: "analyticsadmin_v1alpha.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "alpha", }, { @@ -1528,6 +1574,7 @@ var MicrogenGapicConfigs = []*MicrogenConfig{ ImportPath: "cloud.google.com/go/area120/tables/apiv1alpha1", GRPCServiceConfigPath: "tables_grpc_service_config.json", ApiServiceConfigPath: "area120tables_v1alpha1.yaml", + Transports: []string{"grpc", "rest"}, ReleaseLevel: "alpha", }, { diff --git a/language/apiv1beta2/doc.go b/language/apiv1beta2/doc.go index da93b9d11c73..9b5ba08b2fde 100644 --- a/language/apiv1beta2/doc.go +++ b/language/apiv1beta2/doc.go @@ -73,6 +73,8 @@ package language // import "cloud.google.com/go/language/apiv1beta2" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -162,3 +164,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/language/apiv1beta2/gapic_metadata.json b/language/apiv1beta2/gapic_metadata.json index 8e23997306ce..2afbad75641b 100644 --- a/language/apiv1beta2/gapic_metadata.json +++ b/language/apiv1beta2/gapic_metadata.json @@ -41,6 +41,41 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "AnalyzeEntities": { + "methods": [ + "AnalyzeEntities" + ] + }, + "AnalyzeEntitySentiment": { + "methods": [ + "AnalyzeEntitySentiment" + ] + }, + "AnalyzeSentiment": { + "methods": [ + "AnalyzeSentiment" + ] + }, + "AnalyzeSyntax": { + "methods": [ + "AnalyzeSyntax" + ] + }, + "AnnotateText": { + "methods": [ + "AnnotateText" + ] + }, + "ClassifyText": { + "methods": [ + "ClassifyText" + ] + } + } } } } diff --git a/language/apiv1beta2/language_client.go b/language/apiv1beta2/language_client.go index 15f17ef304cc..bbf7b8dbfc54 100644 --- a/language/apiv1beta2/language_client.go +++ b/language/apiv1beta2/language_client.go @@ -17,18 +17,26 @@ package language import ( + "bytes" "context" + "fmt" + "io/ioutil" "math" + "net/http" + "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" languagepb "google.golang.org/genproto/googleapis/cloud/language/v1beta2" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newClientHook clientHook @@ -132,6 +140,77 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + AnalyzeSentiment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + AnalyzeEntities: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + AnalyzeEntitySentiment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + AnalyzeSyntax: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + ClassifyText: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + AnnotateText: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + } +} + // internalClient is an interface that defines the methods available from Google Cloud Natural Language API. type internalClient interface { Close() error @@ -297,6 +376,75 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new language service rest client. +// +// Provides text analysis operations such as sentiment analysis and entity +// recognition. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://language.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://language.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://language.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) AnalyzeSentiment(ctx context.Context, req *languagepb.AnalyzeSentimentRequest, opts ...gax.CallOption) (*languagepb.AnalyzeSentimentResponse, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) @@ -416,3 +564,351 @@ func (c *gRPCClient) AnnotateText(ctx context.Context, req *languagepb.AnnotateT } return resp, nil } + +// AnalyzeSentiment analyzes the sentiment of the provided text. +func (c *restClient) AnalyzeSentiment(ctx context.Context, req *languagepb.AnalyzeSentimentRequest, opts ...gax.CallOption) (*languagepb.AnalyzeSentimentResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/documents:analyzeSentiment") + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).AnalyzeSentiment[0:len((*c.CallOptions).AnalyzeSentiment):len((*c.CallOptions).AnalyzeSentiment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &languagepb.AnalyzeSentimentResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// AnalyzeEntities finds named entities (currently proper names and common nouns) in the text +// along with entity types, salience, mentions for each entity, and +// other properties. +func (c *restClient) AnalyzeEntities(ctx context.Context, req *languagepb.AnalyzeEntitiesRequest, opts ...gax.CallOption) (*languagepb.AnalyzeEntitiesResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/documents:analyzeEntities") + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).AnalyzeEntities[0:len((*c.CallOptions).AnalyzeEntities):len((*c.CallOptions).AnalyzeEntities)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &languagepb.AnalyzeEntitiesResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// AnalyzeEntitySentiment finds entities, similar to AnalyzeEntities in the text and analyzes +// sentiment associated with each entity and its mentions. +func (c *restClient) AnalyzeEntitySentiment(ctx context.Context, req *languagepb.AnalyzeEntitySentimentRequest, opts ...gax.CallOption) (*languagepb.AnalyzeEntitySentimentResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/documents:analyzeEntitySentiment") + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).AnalyzeEntitySentiment[0:len((*c.CallOptions).AnalyzeEntitySentiment):len((*c.CallOptions).AnalyzeEntitySentiment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &languagepb.AnalyzeEntitySentimentResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// AnalyzeSyntax analyzes the syntax of the text and provides sentence boundaries and +// tokenization along with part-of-speech tags, dependency trees, and other +// properties. +func (c *restClient) AnalyzeSyntax(ctx context.Context, req *languagepb.AnalyzeSyntaxRequest, opts ...gax.CallOption) (*languagepb.AnalyzeSyntaxResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/documents:analyzeSyntax") + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).AnalyzeSyntax[0:len((*c.CallOptions).AnalyzeSyntax):len((*c.CallOptions).AnalyzeSyntax)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &languagepb.AnalyzeSyntaxResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ClassifyText classifies a document into categories. +func (c *restClient) ClassifyText(ctx context.Context, req *languagepb.ClassifyTextRequest, opts ...gax.CallOption) (*languagepb.ClassifyTextResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/documents:classifyText") + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ClassifyText[0:len((*c.CallOptions).ClassifyText):len((*c.CallOptions).ClassifyText)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &languagepb.ClassifyTextResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// AnnotateText a convenience method that provides all syntax, sentiment, entity, and +// classification features in one call. +func (c *restClient) AnnotateText(ctx context.Context, req *languagepb.AnnotateTextRequest, opts ...gax.CallOption) (*languagepb.AnnotateTextResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/documents:annotateText") + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).AnnotateText[0:len((*c.CallOptions).AnnotateText):len((*c.CallOptions).AnnotateText)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &languagepb.AnnotateTextResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/language/apiv1beta2/language_client_example_test.go b/language/apiv1beta2/language_client_example_test.go index c6434eafef3e..1d5b10648d0e 100644 --- a/language/apiv1beta2/language_client_example_test.go +++ b/language/apiv1beta2/language_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := language.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_AnalyzeSentiment() { ctx := context.Background() c, err := language.NewClient(ctx) diff --git a/language/go.mod b/language/go.mod index 2713f444d11d..c6b6ad097af5 100644 --- a/language/go.mod +++ b/language/go.mod @@ -9,4 +9,5 @@ require ( google.golang.org/api v0.84.0 google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad google.golang.org/grpc v1.47.0 + google.golang.org/protobuf v1.28.0 ) diff --git a/lifesciences/apiv2beta/doc.go b/lifesciences/apiv2beta/doc.go index cd78be894135..ec242eb69341 100644 --- a/lifesciences/apiv2beta/doc.go +++ b/lifesciences/apiv2beta/doc.go @@ -77,6 +77,8 @@ package lifesciences // import "cloud.google.com/go/lifesciences/apiv2beta" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -165,3 +167,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/lifesciences/apiv2beta/gapic_metadata.json b/lifesciences/apiv2beta/gapic_metadata.json index d809365ae65e..382dc126efd4 100644 --- a/lifesciences/apiv2beta/gapic_metadata.json +++ b/lifesciences/apiv2beta/gapic_metadata.json @@ -16,6 +16,16 @@ ] } } + }, + "rest": { + "libraryClient": "WorkflowsServiceV2BetaClient", + "rpcs": { + "RunPipeline": { + "methods": [ + "RunPipeline" + ] + } + } } } } diff --git a/lifesciences/apiv2beta/workflows_service_v2_beta_client.go b/lifesciences/apiv2beta/workflows_service_v2_beta_client.go index 695a3f2d587d..da133f5de961 100644 --- a/lifesciences/apiv2beta/workflows_service_v2_beta_client.go +++ b/lifesciences/apiv2beta/workflows_service_v2_beta_client.go @@ -17,22 +17,28 @@ package lifesciences import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" lifesciencespb "google.golang.org/genproto/googleapis/cloud/lifesciences/v2beta" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newWorkflowsServiceV2BetaClientHook clientHook @@ -60,6 +66,12 @@ func defaultWorkflowsServiceV2BetaCallOptions() *WorkflowsServiceV2BetaCallOptio } } +func defaultWorkflowsServiceV2BetaRESTCallOptions() *WorkflowsServiceV2BetaCallOptions { + return &WorkflowsServiceV2BetaCallOptions{ + RunPipeline: []gax.CallOption{}, + } +} + // internalWorkflowsServiceV2BetaClient is an interface that defines the methods available from Cloud Life Sciences API. type internalWorkflowsServiceV2BetaClient interface { Close() error @@ -233,6 +245,90 @@ func (c *workflowsServiceV2BetaGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type workflowsServiceV2BetaRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing WorkflowsServiceV2BetaClient + CallOptions **WorkflowsServiceV2BetaCallOptions +} + +// NewWorkflowsServiceV2BetaRESTClient creates a new workflows service v2 beta rest client. +// +// A service for running workflows, such as pipelines consisting of Docker +// containers. +func NewWorkflowsServiceV2BetaRESTClient(ctx context.Context, opts ...option.ClientOption) (*WorkflowsServiceV2BetaClient, error) { + clientOpts := append(defaultWorkflowsServiceV2BetaRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultWorkflowsServiceV2BetaRESTCallOptions() + c := &workflowsServiceV2BetaRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &WorkflowsServiceV2BetaClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultWorkflowsServiceV2BetaRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://lifesciences.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://lifesciences.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://lifesciences.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *workflowsServiceV2BetaRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *workflowsServiceV2BetaRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *workflowsServiceV2BetaRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *workflowsServiceV2BetaGRPCClient) RunPipeline(ctx context.Context, req *lifesciencespb.RunPipelineRequest, opts ...gax.CallOption) (*RunPipelineOperation, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -257,9 +353,89 @@ func (c *workflowsServiceV2BetaGRPCClient) RunPipeline(ctx context.Context, req }, nil } +// RunPipeline runs a pipeline. The returned Operation’s [metadata] +// [google.longrunning.Operation.metadata] field will contain a +// google.cloud.lifesciences.v2beta.Metadata object describing the status +// of the pipeline execution. The +// response field will contain a +// google.cloud.lifesciences.v2beta.RunPipelineResponse object if the +// pipeline completes successfully. +// +// Note: Before you can use this method, the Life Sciences Service Agent +// must have access to your project. This is done automatically when the +// Cloud Life Sciences API is first enabled, but if you delete this permission +// you must disable and re-enable the API to grant the Life Sciences +// Service Agent the required permissions. +// Authorization requires the following Google +// IAM (at https://cloud.google.com/iam/) permission: +// +// lifesciences.workflows.run +func (c *workflowsServiceV2BetaRESTClient) RunPipeline(ctx context.Context, req *lifesciencespb.RunPipelineRequest, opts ...gax.CallOption) (*RunPipelineOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v2beta/%v/pipelines:run", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v2beta/%s", resp.GetName()) + return &RunPipelineOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + // RunPipelineOperation manages a long-running operation from RunPipeline. type RunPipelineOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // RunPipelineOperation returns a new RunPipelineOperation from a given name. @@ -270,10 +446,21 @@ func (c *workflowsServiceV2BetaGRPCClient) RunPipelineOperation(name string) *Ru } } +// RunPipelineOperation returns a new RunPipelineOperation from a given name. +// The name must be that of a previously created RunPipelineOperation, possibly from a different process. +func (c *workflowsServiceV2BetaRESTClient) RunPipelineOperation(name string) *RunPipelineOperation { + override := fmt.Sprintf("/v2beta/%s", name) + return &RunPipelineOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *RunPipelineOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*lifesciencespb.RunPipelineResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp lifesciencespb.RunPipelineResponse if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -291,6 +478,7 @@ func (op *RunPipelineOperation) Wait(ctx context.Context, opts ...gax.CallOption // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *RunPipelineOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*lifesciencespb.RunPipelineResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp lifesciencespb.RunPipelineResponse if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/lifesciences/apiv2beta/workflows_service_v2_beta_client_example_test.go b/lifesciences/apiv2beta/workflows_service_v2_beta_client_example_test.go index c9e61a6ba403..4043185948c2 100644 --- a/lifesciences/apiv2beta/workflows_service_v2_beta_client_example_test.go +++ b/lifesciences/apiv2beta/workflows_service_v2_beta_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewWorkflowsServiceV2BetaClient() { _ = c } +func ExampleNewWorkflowsServiceV2BetaRESTClient() { + ctx := context.Background() + c, err := lifesciences.NewWorkflowsServiceV2BetaRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleWorkflowsServiceV2BetaClient_RunPipeline() { ctx := context.Background() c, err := lifesciences.NewWorkflowsServiceV2BetaClient(ctx) diff --git a/lifesciences/go.mod b/lifesciences/go.mod index 8d908bb11c37..9c4f83f9df75 100644 --- a/lifesciences/go.mod +++ b/lifesciences/go.mod @@ -8,4 +8,5 @@ require ( google.golang.org/api v0.84.0 google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad google.golang.org/grpc v1.47.0 + google.golang.org/protobuf v1.28.0 ) diff --git a/memcache/apiv1beta2/cloud_memcache_client.go b/memcache/apiv1beta2/cloud_memcache_client.go index b35773b40a3d..10a990dc5d1b 100644 --- a/memcache/apiv1beta2/cloud_memcache_client.go +++ b/memcache/apiv1beta2/cloud_memcache_client.go @@ -17,23 +17,29 @@ package memcache import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" memcachepb "google.golang.org/genproto/googleapis/cloud/memcache/v1beta2" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -76,6 +82,19 @@ func defaultCloudMemcacheCallOptions() *CloudMemcacheCallOptions { } } +func defaultCloudMemcacheRESTCallOptions() *CloudMemcacheCallOptions { + return &CloudMemcacheCallOptions{ + ListInstances: []gax.CallOption{}, + GetInstance: []gax.CallOption{}, + CreateInstance: []gax.CallOption{}, + UpdateInstance: []gax.CallOption{}, + UpdateParameters: []gax.CallOption{}, + DeleteInstance: []gax.CallOption{}, + ApplyParameters: []gax.CallOption{}, + ApplySoftwareUpdate: []gax.CallOption{}, + } +} + // internalCloudMemcacheClient is an interface that defines the methods available from Cloud Memorystore for Memcached API. type internalCloudMemcacheClient interface { Close() error @@ -348,6 +367,107 @@ func (c *cloudMemcacheGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type cloudMemcacheRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing CloudMemcacheClient + CallOptions **CloudMemcacheCallOptions +} + +// NewCloudMemcacheRESTClient creates a new cloud memcache rest client. +// +// Configures and manages Cloud Memorystore for Memcached instances. +// +// The memcache.googleapis.com service implements the Google Cloud Memorystore +// for Memcached API and defines the following resource model for managing +// Memorystore Memcached (also called Memcached below) instances: +// +// The service works with a collection of cloud projects, named: /projects/* +// +// Each project has a collection of available locations, named: /locations/* +// +// Each location has a collection of Memcached instances, named: +// /instances/* +// +// As such, Memcached instances are resources of the form: +// /projects/{project_id}/locations/{location_id}/instances/{instance_id} +// +// Note that location_id must be a GCP region; for example: +// +// projects/my-memcached-project/locations/us-central1/instances/my-memcached +func NewCloudMemcacheRESTClient(ctx context.Context, opts ...option.ClientOption) (*CloudMemcacheClient, error) { + clientOpts := append(defaultCloudMemcacheRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultCloudMemcacheRESTCallOptions() + c := &cloudMemcacheRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &CloudMemcacheClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultCloudMemcacheRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://memcache.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://memcache.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://memcache.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *cloudMemcacheRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *cloudMemcacheRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *cloudMemcacheRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *cloudMemcacheGRPCClient) ListInstances(ctx context.Context, req *memcachepb.ListInstancesRequest, opts ...gax.CallOption) *InstanceIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -559,9 +679,546 @@ func (c *cloudMemcacheGRPCClient) ApplySoftwareUpdate(ctx context.Context, req * }, nil } +// ListInstances lists Instances in a given location. +func (c *cloudMemcacheRESTClient) ListInstances(ctx context.Context, req *memcachepb.ListInstancesRequest, opts ...gax.CallOption) *InstanceIterator { + it := &InstanceIterator{} + req = proto.Clone(req).(*memcachepb.ListInstancesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*memcachepb.Instance, string, error) { + resp := &memcachepb.ListInstancesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v/instances", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetOrderBy() != "" { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetResources(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetInstance gets details of a single Instance. +func (c *cloudMemcacheRESTClient) GetInstance(ctx context.Context, req *memcachepb.GetInstanceRequest, opts ...gax.CallOption) (*memcachepb.Instance, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetInstance[0:len((*c.CallOptions).GetInstance):len((*c.CallOptions).GetInstance)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &memcachepb.Instance{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateInstance creates a new Instance in a given location. +func (c *cloudMemcacheRESTClient) CreateInstance(ctx context.Context, req *memcachepb.CreateInstanceRequest, opts ...gax.CallOption) (*CreateInstanceOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetResource() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v/instances", req.GetParent()) + + params := url.Values{} + params.Add("instanceId", fmt.Sprintf("%v", req.GetInstanceId())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta2/%s", resp.GetName()) + return &CreateInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UpdateInstance updates an existing Instance in a given project and location. +func (c *cloudMemcacheRESTClient) UpdateInstance(ctx context.Context, req *memcachepb.UpdateInstanceRequest, opts ...gax.CallOption) (*UpdateInstanceOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetResource() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v", req.GetResource().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource.name", url.QueryEscape(req.GetResource().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta2/%s", resp.GetName()) + return &UpdateInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UpdateParameters updates the defined Memcached parameters for an existing instance. +// This method only stages the parameters, it must be followed by +// ApplyParameters to apply the parameters to nodes of the Memcached +// instance. +func (c *cloudMemcacheRESTClient) UpdateParameters(ctx context.Context, req *memcachepb.UpdateParametersRequest, opts ...gax.CallOption) (*UpdateParametersOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v:updateParameters", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta2/%s", resp.GetName()) + return &UpdateParametersOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// DeleteInstance deletes a single Instance. +func (c *cloudMemcacheRESTClient) DeleteInstance(ctx context.Context, req *memcachepb.DeleteInstanceRequest, opts ...gax.CallOption) (*DeleteInstanceOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta2/%s", resp.GetName()) + return &DeleteInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ApplyParameters ApplyParameters restarts the set of specified nodes in order to update +// them to the current set of parameters for the Memcached Instance. +func (c *cloudMemcacheRESTClient) ApplyParameters(ctx context.Context, req *memcachepb.ApplyParametersRequest, opts ...gax.CallOption) (*ApplyParametersOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v:applyParameters", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta2/%s", resp.GetName()) + return &ApplyParametersOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ApplySoftwareUpdate updates software on the selected nodes of the Instance. +func (c *cloudMemcacheRESTClient) ApplySoftwareUpdate(ctx context.Context, req *memcachepb.ApplySoftwareUpdateRequest, opts ...gax.CallOption) (*ApplySoftwareUpdateOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/%v:applySoftwareUpdate", req.GetInstance()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "instance", url.QueryEscape(req.GetInstance()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta2/%s", resp.GetName()) + return &ApplySoftwareUpdateOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + // ApplyParametersOperation manages a long-running operation from ApplyParameters. type ApplyParametersOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // ApplyParametersOperation returns a new ApplyParametersOperation from a given name. @@ -572,10 +1229,21 @@ func (c *cloudMemcacheGRPCClient) ApplyParametersOperation(name string) *ApplyPa } } +// ApplyParametersOperation returns a new ApplyParametersOperation from a given name. +// The name must be that of a previously created ApplyParametersOperation, possibly from a different process. +func (c *cloudMemcacheRESTClient) ApplyParametersOperation(name string) *ApplyParametersOperation { + override := fmt.Sprintf("/v1beta2/%s", name) + return &ApplyParametersOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *ApplyParametersOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*memcachepb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp memcachepb.Instance if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -593,6 +1261,7 @@ func (op *ApplyParametersOperation) Wait(ctx context.Context, opts ...gax.CallOp // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *ApplyParametersOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*memcachepb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp memcachepb.Instance if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -630,7 +1299,8 @@ func (op *ApplyParametersOperation) Name() string { // ApplySoftwareUpdateOperation manages a long-running operation from ApplySoftwareUpdate. type ApplySoftwareUpdateOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // ApplySoftwareUpdateOperation returns a new ApplySoftwareUpdateOperation from a given name. @@ -641,10 +1311,21 @@ func (c *cloudMemcacheGRPCClient) ApplySoftwareUpdateOperation(name string) *App } } +// ApplySoftwareUpdateOperation returns a new ApplySoftwareUpdateOperation from a given name. +// The name must be that of a previously created ApplySoftwareUpdateOperation, possibly from a different process. +func (c *cloudMemcacheRESTClient) ApplySoftwareUpdateOperation(name string) *ApplySoftwareUpdateOperation { + override := fmt.Sprintf("/v1beta2/%s", name) + return &ApplySoftwareUpdateOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *ApplySoftwareUpdateOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*memcachepb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp memcachepb.Instance if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -662,6 +1343,7 @@ func (op *ApplySoftwareUpdateOperation) Wait(ctx context.Context, opts ...gax.Ca // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *ApplySoftwareUpdateOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*memcachepb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp memcachepb.Instance if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -699,7 +1381,8 @@ func (op *ApplySoftwareUpdateOperation) Name() string { // CreateInstanceOperation manages a long-running operation from CreateInstance. type CreateInstanceOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // CreateInstanceOperation returns a new CreateInstanceOperation from a given name. @@ -710,10 +1393,21 @@ func (c *cloudMemcacheGRPCClient) CreateInstanceOperation(name string) *CreateIn } } +// CreateInstanceOperation returns a new CreateInstanceOperation from a given name. +// The name must be that of a previously created CreateInstanceOperation, possibly from a different process. +func (c *cloudMemcacheRESTClient) CreateInstanceOperation(name string) *CreateInstanceOperation { + override := fmt.Sprintf("/v1beta2/%s", name) + return &CreateInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *CreateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*memcachepb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp memcachepb.Instance if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -731,6 +1425,7 @@ func (op *CreateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *CreateInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*memcachepb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp memcachepb.Instance if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -768,7 +1463,8 @@ func (op *CreateInstanceOperation) Name() string { // DeleteInstanceOperation manages a long-running operation from DeleteInstance. type DeleteInstanceOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // DeleteInstanceOperation returns a new DeleteInstanceOperation from a given name. @@ -779,10 +1475,21 @@ func (c *cloudMemcacheGRPCClient) DeleteInstanceOperation(name string) *DeleteIn } } +// DeleteInstanceOperation returns a new DeleteInstanceOperation from a given name. +// The name must be that of a previously created DeleteInstanceOperation, possibly from a different process. +func (c *cloudMemcacheRESTClient) DeleteInstanceOperation(name string) *DeleteInstanceOperation { + override := fmt.Sprintf("/v1beta2/%s", name) + return &DeleteInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *DeleteInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -796,6 +1503,7 @@ func (op *DeleteInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeleteInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -826,7 +1534,8 @@ func (op *DeleteInstanceOperation) Name() string { // UpdateInstanceOperation manages a long-running operation from UpdateInstance. type UpdateInstanceOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UpdateInstanceOperation returns a new UpdateInstanceOperation from a given name. @@ -837,10 +1546,21 @@ func (c *cloudMemcacheGRPCClient) UpdateInstanceOperation(name string) *UpdateIn } } +// UpdateInstanceOperation returns a new UpdateInstanceOperation from a given name. +// The name must be that of a previously created UpdateInstanceOperation, possibly from a different process. +func (c *cloudMemcacheRESTClient) UpdateInstanceOperation(name string) *UpdateInstanceOperation { + override := fmt.Sprintf("/v1beta2/%s", name) + return &UpdateInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UpdateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*memcachepb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp memcachepb.Instance if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -858,6 +1578,7 @@ func (op *UpdateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UpdateInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*memcachepb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp memcachepb.Instance if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -895,7 +1616,8 @@ func (op *UpdateInstanceOperation) Name() string { // UpdateParametersOperation manages a long-running operation from UpdateParameters. type UpdateParametersOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UpdateParametersOperation returns a new UpdateParametersOperation from a given name. @@ -906,10 +1628,21 @@ func (c *cloudMemcacheGRPCClient) UpdateParametersOperation(name string) *Update } } +// UpdateParametersOperation returns a new UpdateParametersOperation from a given name. +// The name must be that of a previously created UpdateParametersOperation, possibly from a different process. +func (c *cloudMemcacheRESTClient) UpdateParametersOperation(name string) *UpdateParametersOperation { + override := fmt.Sprintf("/v1beta2/%s", name) + return &UpdateParametersOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UpdateParametersOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*memcachepb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp memcachepb.Instance if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -927,6 +1660,7 @@ func (op *UpdateParametersOperation) Wait(ctx context.Context, opts ...gax.CallO // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UpdateParametersOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*memcachepb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp memcachepb.Instance if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/memcache/apiv1beta2/cloud_memcache_client_example_test.go b/memcache/apiv1beta2/cloud_memcache_client_example_test.go index ef4a696e0f6f..eadd6de3b054 100644 --- a/memcache/apiv1beta2/cloud_memcache_client_example_test.go +++ b/memcache/apiv1beta2/cloud_memcache_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewCloudMemcacheClient() { _ = c } +func ExampleNewCloudMemcacheRESTClient() { + ctx := context.Background() + c, err := memcache.NewCloudMemcacheRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleCloudMemcacheClient_ListInstances() { ctx := context.Background() c, err := memcache.NewCloudMemcacheClient(ctx) diff --git a/memcache/apiv1beta2/doc.go b/memcache/apiv1beta2/doc.go index aa7e888c24ea..30f78b92188f 100644 --- a/memcache/apiv1beta2/doc.go +++ b/memcache/apiv1beta2/doc.go @@ -78,6 +78,8 @@ package memcache // import "cloud.google.com/go/memcache/apiv1beta2" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -166,3 +168,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/memcache/apiv1beta2/gapic_metadata.json b/memcache/apiv1beta2/gapic_metadata.json index 6efa801fe86b..eb4247c068d0 100644 --- a/memcache/apiv1beta2/gapic_metadata.json +++ b/memcache/apiv1beta2/gapic_metadata.json @@ -51,6 +51,51 @@ ] } } + }, + "rest": { + "libraryClient": "CloudMemcacheClient", + "rpcs": { + "ApplyParameters": { + "methods": [ + "ApplyParameters" + ] + }, + "ApplySoftwareUpdate": { + "methods": [ + "ApplySoftwareUpdate" + ] + }, + "CreateInstance": { + "methods": [ + "CreateInstance" + ] + }, + "DeleteInstance": { + "methods": [ + "DeleteInstance" + ] + }, + "GetInstance": { + "methods": [ + "GetInstance" + ] + }, + "ListInstances": { + "methods": [ + "ListInstances" + ] + }, + "UpdateInstance": { + "methods": [ + "UpdateInstance" + ] + }, + "UpdateParameters": { + "methods": [ + "UpdateParameters" + ] + } + } } } } diff --git a/metastore/apiv1beta/dataproc_metastore_client.go b/metastore/apiv1beta/dataproc_metastore_client.go index 51e279b9046d..4cdfa59c09c1 100644 --- a/metastore/apiv1beta/dataproc_metastore_client.go +++ b/metastore/apiv1beta/dataproc_metastore_client.go @@ -17,24 +17,30 @@ package metastore import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" metastorepb "google.golang.org/genproto/googleapis/cloud/metastore/v1beta" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -151,6 +157,80 @@ func defaultDataprocMetastoreCallOptions() *DataprocMetastoreCallOptions { } } +func defaultDataprocMetastoreRESTCallOptions() *DataprocMetastoreCallOptions { + return &DataprocMetastoreCallOptions{ + ListServices: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetService: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateService: []gax.CallOption{}, + UpdateService: []gax.CallOption{}, + DeleteService: []gax.CallOption{}, + ListMetadataImports: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetMetadataImport: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateMetadataImport: []gax.CallOption{}, + UpdateMetadataImport: []gax.CallOption{}, + ExportMetadata: []gax.CallOption{}, + RestoreService: []gax.CallOption{}, + ListBackups: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetBackup: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 10000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateBackup: []gax.CallOption{}, + DeleteBackup: []gax.CallOption{}, + } +} + // internalDataprocMetastoreClient is an interface that defines the methods available from Dataproc Metastore API. type internalDataprocMetastoreClient interface { Close() error @@ -485,6 +565,108 @@ func (c *dataprocMetastoreGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type dataprocMetastoreRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing DataprocMetastoreClient + CallOptions **DataprocMetastoreCallOptions +} + +// NewDataprocMetastoreRESTClient creates a new dataproc metastore rest client. +// +// Configures and manages metastore services. +// Metastore services are fully managed, highly available, auto-scaled, +// auto-healing, OSS-native deployments of technical metadata management +// software. Each metastore service exposes a network endpoint through which +// metadata queries are served. Metadata queries can originate from a variety +// of sources, including Apache Hive, Apache Presto, and Apache Spark. +// +// The Dataproc Metastore API defines the following resource model: +// +// The service works with a collection of Google Cloud projects, named: +// /projects/* +// +// Each project has a collection of available locations, named: /locations/* +// (a location must refer to a Google Cloud region) +// +// Each location has a collection of services, named: /services/* +// +// Dataproc Metastore services are resources with names of the form: +// +// /projects/{project_number}/locations/{location_id}/services/{service_id}. +func NewDataprocMetastoreRESTClient(ctx context.Context, opts ...option.ClientOption) (*DataprocMetastoreClient, error) { + clientOpts := append(defaultDataprocMetastoreRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultDataprocMetastoreRESTCallOptions() + c := &dataprocMetastoreRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &DataprocMetastoreClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultDataprocMetastoreRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://metastore.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://metastore.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://metastore.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *dataprocMetastoreRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *dataprocMetastoreRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *dataprocMetastoreRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *dataprocMetastoreGRPCClient) ListServices(ctx context.Context, req *metastorepb.ListServicesRequest, opts ...gax.CallOption) *ServiceIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -902,85 +1084,1166 @@ func (c *dataprocMetastoreGRPCClient) DeleteBackup(ctx context.Context, req *met }, nil } -// CreateBackupOperation manages a long-running operation from CreateBackup. -type CreateBackupOperation struct { - lro *longrunning.Operation -} +// ListServices lists services in a project and location. +func (c *dataprocMetastoreRESTClient) ListServices(ctx context.Context, req *metastorepb.ListServicesRequest, opts ...gax.CallOption) *ServiceIterator { + it := &ServiceIterator{} + req = proto.Clone(req).(*metastorepb.ListServicesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*metastorepb.Service, string, error) { + resp := &metastorepb.ListServicesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/services", req.GetParent()) -// CreateBackupOperation returns a new CreateBackupOperation from a given name. -// The name must be that of a previously created CreateBackupOperation, possibly from a different process. -func (c *dataprocMetastoreGRPCClient) CreateBackupOperation(name string) *CreateBackupOperation { - return &CreateBackupOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetOrderBy() != "" { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetServices(), resp.GetNextPageToken(), nil } -} -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. -// -// See documentation of Poll for error-handling information. -func (op *CreateBackupOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*metastorepb.Backup, error) { - var resp metastorepb.Backup - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - return &resp, nil + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it } -// Poll fetches the latest state of the long-running operation. -// -// Poll also fetches the latest metadata, which can be retrieved by Metadata. -// -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *CreateBackupOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*metastorepb.Backup, error) { - var resp metastorepb.Backup - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { +// GetService gets the details of a single service. +func (c *dataprocMetastoreRESTClient) GetService(ctx context.Context, req *metastorepb.GetServiceRequest, opts ...gax.CallOption) (*metastorepb.Service, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - if !op.Done() { - return nil, nil + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetService[0:len((*c.CallOptions).GetService):len((*c.CallOptions).GetService)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &metastorepb.Service{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e } - return &resp, nil + return resp, nil } -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. -// If the metadata is not available, the returned metadata and error are both nil. -func (op *CreateBackupOperation) Metadata() (*metastorepb.OperationMetadata, error) { - var meta metastorepb.OperationMetadata - if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { - return nil, nil - } else if err != nil { +// CreateService creates a metastore service in a project and location. +func (c *dataprocMetastoreRESTClient) CreateService(ctx context.Context, req *metastorepb.CreateServiceRequest, opts ...gax.CallOption) (*CreateServiceOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetService() + jsonReq, err := m.Marshal(body) + if err != nil { return nil, err } - return &meta, nil -} -// Done reports whether the long-running operation has completed. -func (op *CreateBackupOperation) Done() bool { - return op.lro.Done() -} + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/services", req.GetParent()) -// Name returns the name of the long-running operation. -// The name is assigned by the server and is unique within the service from which the operation is created. -func (op *CreateBackupOperation) Name() string { - return op.lro.Name() -} + params := url.Values{} + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + params.Add("serviceId", fmt.Sprintf("%v", req.GetServiceId())) -// CreateMetadataImportOperation manages a long-running operation from CreateMetadataImport. -type CreateMetadataImportOperation struct { - lro *longrunning.Operation -} + baseUrl.RawQuery = params.Encode() -// CreateMetadataImportOperation returns a new CreateMetadataImportOperation from a given name. -// The name must be that of a previously created CreateMetadataImportOperation, possibly from a different process. -func (c *dataprocMetastoreGRPCClient) CreateMetadataImportOperation(name string) *CreateMetadataImportOperation { - return &CreateMetadataImportOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta/%s", resp.GetName()) + return &CreateServiceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UpdateService updates the parameters of a single service. +func (c *dataprocMetastoreRESTClient) UpdateService(ctx context.Context, req *metastorepb.UpdateServiceRequest, opts ...gax.CallOption) (*UpdateServiceOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetService() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetService().GetName()) + + params := url.Values{} + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "service.name", url.QueryEscape(req.GetService().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta/%s", resp.GetName()) + return &UpdateServiceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// DeleteService deletes a single service. +func (c *dataprocMetastoreRESTClient) DeleteService(ctx context.Context, req *metastorepb.DeleteServiceRequest, opts ...gax.CallOption) (*DeleteServiceOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + params := url.Values{} + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta/%s", resp.GetName()) + return &DeleteServiceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ListMetadataImports lists imports in a service. +func (c *dataprocMetastoreRESTClient) ListMetadataImports(ctx context.Context, req *metastorepb.ListMetadataImportsRequest, opts ...gax.CallOption) *MetadataImportIterator { + it := &MetadataImportIterator{} + req = proto.Clone(req).(*metastorepb.ListMetadataImportsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*metastorepb.MetadataImport, string, error) { + resp := &metastorepb.ListMetadataImportsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/metadataImports", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetOrderBy() != "" { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetMetadataImports(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetMetadataImport gets details of a single import. +func (c *dataprocMetastoreRESTClient) GetMetadataImport(ctx context.Context, req *metastorepb.GetMetadataImportRequest, opts ...gax.CallOption) (*metastorepb.MetadataImport, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetMetadataImport[0:len((*c.CallOptions).GetMetadataImport):len((*c.CallOptions).GetMetadataImport)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &metastorepb.MetadataImport{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateMetadataImport creates a new MetadataImport in a given project and location. +func (c *dataprocMetastoreRESTClient) CreateMetadataImport(ctx context.Context, req *metastorepb.CreateMetadataImportRequest, opts ...gax.CallOption) (*CreateMetadataImportOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetMetadataImport() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/metadataImports", req.GetParent()) + + params := url.Values{} + params.Add("metadataImportId", fmt.Sprintf("%v", req.GetMetadataImportId())) + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta/%s", resp.GetName()) + return &CreateMetadataImportOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UpdateMetadataImport updates a single import. +// Only the description field of MetadataImport is supported to be updated. +func (c *dataprocMetastoreRESTClient) UpdateMetadataImport(ctx context.Context, req *metastorepb.UpdateMetadataImportRequest, opts ...gax.CallOption) (*UpdateMetadataImportOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetMetadataImport() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetMetadataImport().GetName()) + + params := url.Values{} + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "metadata_import.name", url.QueryEscape(req.GetMetadataImport().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta/%s", resp.GetName()) + return &UpdateMetadataImportOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ExportMetadata exports metadata from a service. +func (c *dataprocMetastoreRESTClient) ExportMetadata(ctx context.Context, req *metastorepb.ExportMetadataRequest, opts ...gax.CallOption) (*ExportMetadataOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v:exportMetadata", req.GetService()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "service", url.QueryEscape(req.GetService()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta/%s", resp.GetName()) + return &ExportMetadataOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// RestoreService restores a service from a backup. +func (c *dataprocMetastoreRESTClient) RestoreService(ctx context.Context, req *metastorepb.RestoreServiceRequest, opts ...gax.CallOption) (*RestoreServiceOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v:restore", req.GetService()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "service", url.QueryEscape(req.GetService()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta/%s", resp.GetName()) + return &RestoreServiceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ListBackups lists backups in a service. +func (c *dataprocMetastoreRESTClient) ListBackups(ctx context.Context, req *metastorepb.ListBackupsRequest, opts ...gax.CallOption) *BackupIterator { + it := &BackupIterator{} + req = proto.Clone(req).(*metastorepb.ListBackupsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*metastorepb.Backup, string, error) { + resp := &metastorepb.ListBackupsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/backups", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetOrderBy() != "" { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetBackups(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetBackup gets details of a single backup. +func (c *dataprocMetastoreRESTClient) GetBackup(ctx context.Context, req *metastorepb.GetBackupRequest, opts ...gax.CallOption) (*metastorepb.Backup, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetBackup[0:len((*c.CallOptions).GetBackup):len((*c.CallOptions).GetBackup)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &metastorepb.Backup{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateBackup creates a new Backup in a given project and location. +func (c *dataprocMetastoreRESTClient) CreateBackup(ctx context.Context, req *metastorepb.CreateBackupRequest, opts ...gax.CallOption) (*CreateBackupOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetBackup() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/backups", req.GetParent()) + + params := url.Values{} + params.Add("backupId", fmt.Sprintf("%v", req.GetBackupId())) + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta/%s", resp.GetName()) + return &CreateBackupOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// DeleteBackup deletes a single backup. +func (c *dataprocMetastoreRESTClient) DeleteBackup(ctx context.Context, req *metastorepb.DeleteBackupRequest, opts ...gax.CallOption) (*DeleteBackupOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + params := url.Values{} + if req.GetRequestId() != "" { + params.Add("requestId", fmt.Sprintf("%v", req.GetRequestId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta/%s", resp.GetName()) + return &DeleteBackupOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// CreateBackupOperation manages a long-running operation from CreateBackup. +type CreateBackupOperation struct { + lro *longrunning.Operation + pollPath string +} + +// CreateBackupOperation returns a new CreateBackupOperation from a given name. +// The name must be that of a previously created CreateBackupOperation, possibly from a different process. +func (c *dataprocMetastoreGRPCClient) CreateBackupOperation(name string) *CreateBackupOperation { + return &CreateBackupOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// CreateBackupOperation returns a new CreateBackupOperation from a given name. +// The name must be that of a previously created CreateBackupOperation, possibly from a different process. +func (c *dataprocMetastoreRESTClient) CreateBackupOperation(name string) *CreateBackupOperation { + override := fmt.Sprintf("/v1beta/%s", name) + return &CreateBackupOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateBackupOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*metastorepb.Backup, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp metastorepb.Backup + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateBackupOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*metastorepb.Backup, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp metastorepb.Backup + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateBackupOperation) Metadata() (*metastorepb.OperationMetadata, error) { + var meta metastorepb.OperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateBackupOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *CreateBackupOperation) Name() string { + return op.lro.Name() +} + +// CreateMetadataImportOperation manages a long-running operation from CreateMetadataImport. +type CreateMetadataImportOperation struct { + lro *longrunning.Operation + pollPath string +} + +// CreateMetadataImportOperation returns a new CreateMetadataImportOperation from a given name. +// The name must be that of a previously created CreateMetadataImportOperation, possibly from a different process. +func (c *dataprocMetastoreGRPCClient) CreateMetadataImportOperation(name string) *CreateMetadataImportOperation { + return &CreateMetadataImportOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// CreateMetadataImportOperation returns a new CreateMetadataImportOperation from a given name. +// The name must be that of a previously created CreateMetadataImportOperation, possibly from a different process. +func (c *dataprocMetastoreRESTClient) CreateMetadataImportOperation(name string) *CreateMetadataImportOperation { + override := fmt.Sprintf("/v1beta/%s", name) + return &CreateMetadataImportOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, } } @@ -988,6 +2251,7 @@ func (c *dataprocMetastoreGRPCClient) CreateMetadataImportOperation(name string) // // See documentation of Poll for error-handling information. func (op *CreateMetadataImportOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*metastorepb.MetadataImport, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp metastorepb.MetadataImport if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1005,6 +2269,7 @@ func (op *CreateMetadataImportOperation) Wait(ctx context.Context, opts ...gax.C // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *CreateMetadataImportOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*metastorepb.MetadataImport, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp metastorepb.MetadataImport if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1042,7 +2307,8 @@ func (op *CreateMetadataImportOperation) Name() string { // CreateServiceOperation manages a long-running operation from CreateService. type CreateServiceOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // CreateServiceOperation returns a new CreateServiceOperation from a given name. @@ -1053,10 +2319,21 @@ func (c *dataprocMetastoreGRPCClient) CreateServiceOperation(name string) *Creat } } +// CreateServiceOperation returns a new CreateServiceOperation from a given name. +// The name must be that of a previously created CreateServiceOperation, possibly from a different process. +func (c *dataprocMetastoreRESTClient) CreateServiceOperation(name string) *CreateServiceOperation { + override := fmt.Sprintf("/v1beta/%s", name) + return &CreateServiceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *CreateServiceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*metastorepb.Service, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp metastorepb.Service if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1074,6 +2351,7 @@ func (op *CreateServiceOperation) Wait(ctx context.Context, opts ...gax.CallOpti // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *CreateServiceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*metastorepb.Service, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp metastorepb.Service if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1111,7 +2389,8 @@ func (op *CreateServiceOperation) Name() string { // DeleteBackupOperation manages a long-running operation from DeleteBackup. type DeleteBackupOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // DeleteBackupOperation returns a new DeleteBackupOperation from a given name. @@ -1122,10 +2401,21 @@ func (c *dataprocMetastoreGRPCClient) DeleteBackupOperation(name string) *Delete } } +// DeleteBackupOperation returns a new DeleteBackupOperation from a given name. +// The name must be that of a previously created DeleteBackupOperation, possibly from a different process. +func (c *dataprocMetastoreRESTClient) DeleteBackupOperation(name string) *DeleteBackupOperation { + override := fmt.Sprintf("/v1beta/%s", name) + return &DeleteBackupOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *DeleteBackupOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1139,6 +2429,7 @@ func (op *DeleteBackupOperation) Wait(ctx context.Context, opts ...gax.CallOptio // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeleteBackupOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1169,7 +2460,8 @@ func (op *DeleteBackupOperation) Name() string { // DeleteServiceOperation manages a long-running operation from DeleteService. type DeleteServiceOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // DeleteServiceOperation returns a new DeleteServiceOperation from a given name. @@ -1180,10 +2472,21 @@ func (c *dataprocMetastoreGRPCClient) DeleteServiceOperation(name string) *Delet } } +// DeleteServiceOperation returns a new DeleteServiceOperation from a given name. +// The name must be that of a previously created DeleteServiceOperation, possibly from a different process. +func (c *dataprocMetastoreRESTClient) DeleteServiceOperation(name string) *DeleteServiceOperation { + override := fmt.Sprintf("/v1beta/%s", name) + return &DeleteServiceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *DeleteServiceOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1197,6 +2500,7 @@ func (op *DeleteServiceOperation) Wait(ctx context.Context, opts ...gax.CallOpti // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeleteServiceOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1227,7 +2531,8 @@ func (op *DeleteServiceOperation) Name() string { // ExportMetadataOperation manages a long-running operation from ExportMetadata. type ExportMetadataOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // ExportMetadataOperation returns a new ExportMetadataOperation from a given name. @@ -1238,10 +2543,21 @@ func (c *dataprocMetastoreGRPCClient) ExportMetadataOperation(name string) *Expo } } +// ExportMetadataOperation returns a new ExportMetadataOperation from a given name. +// The name must be that of a previously created ExportMetadataOperation, possibly from a different process. +func (c *dataprocMetastoreRESTClient) ExportMetadataOperation(name string) *ExportMetadataOperation { + override := fmt.Sprintf("/v1beta/%s", name) + return &ExportMetadataOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *ExportMetadataOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*metastorepb.MetadataExport, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp metastorepb.MetadataExport if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1259,6 +2575,7 @@ func (op *ExportMetadataOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *ExportMetadataOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*metastorepb.MetadataExport, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp metastorepb.MetadataExport if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1296,7 +2613,8 @@ func (op *ExportMetadataOperation) Name() string { // RestoreServiceOperation manages a long-running operation from RestoreService. type RestoreServiceOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // RestoreServiceOperation returns a new RestoreServiceOperation from a given name. @@ -1307,10 +2625,21 @@ func (c *dataprocMetastoreGRPCClient) RestoreServiceOperation(name string) *Rest } } +// RestoreServiceOperation returns a new RestoreServiceOperation from a given name. +// The name must be that of a previously created RestoreServiceOperation, possibly from a different process. +func (c *dataprocMetastoreRESTClient) RestoreServiceOperation(name string) *RestoreServiceOperation { + override := fmt.Sprintf("/v1beta/%s", name) + return &RestoreServiceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *RestoreServiceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*metastorepb.Restore, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp metastorepb.Restore if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1328,6 +2657,7 @@ func (op *RestoreServiceOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *RestoreServiceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*metastorepb.Restore, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp metastorepb.Restore if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1365,7 +2695,8 @@ func (op *RestoreServiceOperation) Name() string { // UpdateMetadataImportOperation manages a long-running operation from UpdateMetadataImport. type UpdateMetadataImportOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UpdateMetadataImportOperation returns a new UpdateMetadataImportOperation from a given name. @@ -1376,10 +2707,21 @@ func (c *dataprocMetastoreGRPCClient) UpdateMetadataImportOperation(name string) } } +// UpdateMetadataImportOperation returns a new UpdateMetadataImportOperation from a given name. +// The name must be that of a previously created UpdateMetadataImportOperation, possibly from a different process. +func (c *dataprocMetastoreRESTClient) UpdateMetadataImportOperation(name string) *UpdateMetadataImportOperation { + override := fmt.Sprintf("/v1beta/%s", name) + return &UpdateMetadataImportOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UpdateMetadataImportOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*metastorepb.MetadataImport, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp metastorepb.MetadataImport if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1397,6 +2739,7 @@ func (op *UpdateMetadataImportOperation) Wait(ctx context.Context, opts ...gax.C // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UpdateMetadataImportOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*metastorepb.MetadataImport, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp metastorepb.MetadataImport if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1434,7 +2777,8 @@ func (op *UpdateMetadataImportOperation) Name() string { // UpdateServiceOperation manages a long-running operation from UpdateService. type UpdateServiceOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UpdateServiceOperation returns a new UpdateServiceOperation from a given name. @@ -1445,10 +2789,21 @@ func (c *dataprocMetastoreGRPCClient) UpdateServiceOperation(name string) *Updat } } +// UpdateServiceOperation returns a new UpdateServiceOperation from a given name. +// The name must be that of a previously created UpdateServiceOperation, possibly from a different process. +func (c *dataprocMetastoreRESTClient) UpdateServiceOperation(name string) *UpdateServiceOperation { + override := fmt.Sprintf("/v1beta/%s", name) + return &UpdateServiceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UpdateServiceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*metastorepb.Service, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp metastorepb.Service if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1466,6 +2821,7 @@ func (op *UpdateServiceOperation) Wait(ctx context.Context, opts ...gax.CallOpti // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UpdateServiceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*metastorepb.Service, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp metastorepb.Service if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/metastore/apiv1beta/dataproc_metastore_client_example_test.go b/metastore/apiv1beta/dataproc_metastore_client_example_test.go index 82103f72ebe4..037c678ae7aa 100644 --- a/metastore/apiv1beta/dataproc_metastore_client_example_test.go +++ b/metastore/apiv1beta/dataproc_metastore_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewDataprocMetastoreClient() { _ = c } +func ExampleNewDataprocMetastoreRESTClient() { + ctx := context.Background() + c, err := metastore.NewDataprocMetastoreRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleDataprocMetastoreClient_ListServices() { ctx := context.Background() c, err := metastore.NewDataprocMetastoreClient(ctx) diff --git a/metastore/apiv1beta/doc.go b/metastore/apiv1beta/doc.go index 57740a9b2795..43934db7626e 100644 --- a/metastore/apiv1beta/doc.go +++ b/metastore/apiv1beta/doc.go @@ -78,6 +78,8 @@ package metastore // import "cloud.google.com/go/metastore/apiv1beta" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -166,3 +168,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/metastore/apiv1beta/gapic_metadata.json b/metastore/apiv1beta/gapic_metadata.json index 187c53166785..3f39c6afdfa3 100644 --- a/metastore/apiv1beta/gapic_metadata.json +++ b/metastore/apiv1beta/gapic_metadata.json @@ -86,6 +86,86 @@ ] } } + }, + "rest": { + "libraryClient": "DataprocMetastoreClient", + "rpcs": { + "CreateBackup": { + "methods": [ + "CreateBackup" + ] + }, + "CreateMetadataImport": { + "methods": [ + "CreateMetadataImport" + ] + }, + "CreateService": { + "methods": [ + "CreateService" + ] + }, + "DeleteBackup": { + "methods": [ + "DeleteBackup" + ] + }, + "DeleteService": { + "methods": [ + "DeleteService" + ] + }, + "ExportMetadata": { + "methods": [ + "ExportMetadata" + ] + }, + "GetBackup": { + "methods": [ + "GetBackup" + ] + }, + "GetMetadataImport": { + "methods": [ + "GetMetadataImport" + ] + }, + "GetService": { + "methods": [ + "GetService" + ] + }, + "ListBackups": { + "methods": [ + "ListBackups" + ] + }, + "ListMetadataImports": { + "methods": [ + "ListMetadataImports" + ] + }, + "ListServices": { + "methods": [ + "ListServices" + ] + }, + "RestoreService": { + "methods": [ + "RestoreService" + ] + }, + "UpdateMetadataImport": { + "methods": [ + "UpdateMetadataImport" + ] + }, + "UpdateService": { + "methods": [ + "UpdateService" + ] + } + } } } } diff --git a/osconfig/agentendpoint/apiv1beta/agent_endpoint_client.go b/osconfig/agentendpoint/apiv1beta/agent_endpoint_client.go index c7d686464820..b76a4fcb5480 100644 --- a/osconfig/agentendpoint/apiv1beta/agent_endpoint_client.go +++ b/osconfig/agentendpoint/apiv1beta/agent_endpoint_client.go @@ -18,17 +18,24 @@ package agentendpoint import ( "context" + "fmt" + "io/ioutil" "math" + "net/http" + "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" agentendpointpb "google.golang.org/genproto/googleapis/cloud/osconfig/agentendpoint/v1beta" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newClientHook clientHook @@ -130,6 +137,75 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + ReceiveTaskNotification: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + 499, + http.StatusConflict, + http.StatusInternalServerError, + http.StatusServiceUnavailable) + }), + }, + StartNextTask: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ReportTaskProgress: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ReportTaskComplete: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + LookupEffectiveGuestPolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + RegisterAgent: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + } +} + // internalClient is an interface that defines the methods available from OS Config API. type internalClient interface { Close() error @@ -289,6 +365,74 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new agent endpoint service rest client. +// +// OS Config agent endpoint API. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://osconfig.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://osconfig.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://osconfig.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) ReceiveTaskNotification(ctx context.Context, req *agentendpointpb.ReceiveTaskNotificationRequest, opts ...gax.CallOption) (agentendpointpb.AgentEndpointService_ReceiveTaskNotificationClient, error) { ctx = insertMetadata(ctx, c.xGoogMetadata) var resp agentendpointpb.AgentEndpointService_ReceiveTaskNotificationClient @@ -402,3 +546,419 @@ func (c *gRPCClient) RegisterAgent(ctx context.Context, req *agentendpointpb.Reg } return resp, nil } + +// ReceiveTaskNotification stream established by client to receive Task notifications. +func (c *restClient) ReceiveTaskNotification(ctx context.Context, req *agentendpointpb.ReceiveTaskNotificationRequest, opts ...gax.CallOption) (agentendpointpb.AgentEndpointService_ReceiveTaskNotificationClient, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("") + + params := url.Values{} + params.Add("agentVersion", fmt.Sprintf("%v", req.GetAgentVersion())) + params.Add("instanceIdToken", fmt.Sprintf("%v", req.GetInstanceIdToken())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + var streamClient *receiveTaskNotificationRESTClient + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + streamClient = &receiveTaskNotificationRESTClient{ + ctx: ctx, + md: metadata.MD(httpRsp.Header), + stream: gax.NewProtoJSONStreamReader(httpRsp.Body, (&agentendpointpb.ReceiveTaskNotificationResponse{}).ProtoReflect().Type()), + } + return nil + }, opts...) + + return streamClient, e +} + +// receiveTaskNotificationRESTClient is the stream client used to consume the server stream created by +// the REST implementation of ReceiveTaskNotification. +type receiveTaskNotificationRESTClient struct { + ctx context.Context + md metadata.MD + stream *gax.ProtoJSONStream +} + +func (c *receiveTaskNotificationRESTClient) Recv() (*agentendpointpb.ReceiveTaskNotificationResponse, error) { + if err := c.ctx.Err(); err != nil { + defer c.stream.Close() + return nil, err + } + msg, err := c.stream.Recv() + if err != nil { + defer c.stream.Close() + return nil, err + } + res := msg.(*agentendpointpb.ReceiveTaskNotificationResponse) + return res, nil +} + +func (c *receiveTaskNotificationRESTClient) Header() (metadata.MD, error) { + return c.md, nil +} + +func (c *receiveTaskNotificationRESTClient) Trailer() metadata.MD { + return c.md +} + +func (c *receiveTaskNotificationRESTClient) CloseSend() error { + // This is a no-op to fulfill the interface. + return fmt.Errorf("this method is not implemented for a server-stream") +} + +func (c *receiveTaskNotificationRESTClient) Context() context.Context { + return c.ctx +} + +func (c *receiveTaskNotificationRESTClient) SendMsg(m interface{}) error { + // This is a no-op to fulfill the interface. + return fmt.Errorf("this method is not implemented for a server-stream") +} + +func (c *receiveTaskNotificationRESTClient) RecvMsg(m interface{}) error { + // This is a no-op to fulfill the interface. + return fmt.Errorf("this method is not implemented, use Recv") +} + +// StartNextTask signals the start of a task execution and returns the task info. +func (c *restClient) StartNextTask(ctx context.Context, req *agentendpointpb.StartNextTaskRequest, opts ...gax.CallOption) (*agentendpointpb.StartNextTaskResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("") + + params := url.Values{} + params.Add("instanceIdToken", fmt.Sprintf("%v", req.GetInstanceIdToken())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).StartNextTask[0:len((*c.CallOptions).StartNextTask):len((*c.CallOptions).StartNextTask)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &agentendpointpb.StartNextTaskResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ReportTaskProgress signals an intermediary progress checkpoint in task execution. +func (c *restClient) ReportTaskProgress(ctx context.Context, req *agentendpointpb.ReportTaskProgressRequest, opts ...gax.CallOption) (*agentendpointpb.ReportTaskProgressResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("") + + params := url.Values{} + params.Add("applyPatchesTaskProgress.state", fmt.Sprintf("%v", req.GetApplyPatchesTaskProgress().GetState())) + params.Add("execStepTaskProgress.state", fmt.Sprintf("%v", req.GetExecStepTaskProgress().GetState())) + params.Add("instanceIdToken", fmt.Sprintf("%v", req.GetInstanceIdToken())) + params.Add("taskId", fmt.Sprintf("%v", req.GetTaskId())) + params.Add("taskType", fmt.Sprintf("%v", req.GetTaskType())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ReportTaskProgress[0:len((*c.CallOptions).ReportTaskProgress):len((*c.CallOptions).ReportTaskProgress)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &agentendpointpb.ReportTaskProgressResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ReportTaskComplete signals that the task execution is complete and optionally returns the next +// task. +func (c *restClient) ReportTaskComplete(ctx context.Context, req *agentendpointpb.ReportTaskCompleteRequest, opts ...gax.CallOption) (*agentendpointpb.ReportTaskCompleteResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("") + + params := url.Values{} + params.Add("applyPatchesTaskOutput.state", fmt.Sprintf("%v", req.GetApplyPatchesTaskOutput().GetState())) + if req.GetErrorMessage() != "" { + params.Add("errorMessage", fmt.Sprintf("%v", req.GetErrorMessage())) + } + params.Add("execStepTaskOutput.exitCode", fmt.Sprintf("%v", req.GetExecStepTaskOutput().GetExitCode())) + params.Add("execStepTaskOutput.state", fmt.Sprintf("%v", req.GetExecStepTaskOutput().GetState())) + params.Add("instanceIdToken", fmt.Sprintf("%v", req.GetInstanceIdToken())) + params.Add("taskId", fmt.Sprintf("%v", req.GetTaskId())) + params.Add("taskType", fmt.Sprintf("%v", req.GetTaskType())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ReportTaskComplete[0:len((*c.CallOptions).ReportTaskComplete):len((*c.CallOptions).ReportTaskComplete)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &agentendpointpb.ReportTaskCompleteResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// LookupEffectiveGuestPolicy lookup the effective guest policy that applies to a VM instance. This +// lookup merges all policies that are assigned to the instance ancestry. +func (c *restClient) LookupEffectiveGuestPolicy(ctx context.Context, req *agentendpointpb.LookupEffectiveGuestPolicyRequest, opts ...gax.CallOption) (*agentendpointpb.EffectiveGuestPolicy, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("") + + params := url.Values{} + params.Add("instanceIdToken", fmt.Sprintf("%v", req.GetInstanceIdToken())) + if req.GetOsArchitecture() != "" { + params.Add("osArchitecture", fmt.Sprintf("%v", req.GetOsArchitecture())) + } + if req.GetOsShortName() != "" { + params.Add("osShortName", fmt.Sprintf("%v", req.GetOsShortName())) + } + if req.GetOsVersion() != "" { + params.Add("osVersion", fmt.Sprintf("%v", req.GetOsVersion())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).LookupEffectiveGuestPolicy[0:len((*c.CallOptions).LookupEffectiveGuestPolicy):len((*c.CallOptions).LookupEffectiveGuestPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &agentendpointpb.EffectiveGuestPolicy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// RegisterAgent registers the agent running on the VM. +func (c *restClient) RegisterAgent(ctx context.Context, req *agentendpointpb.RegisterAgentRequest, opts ...gax.CallOption) (*agentendpointpb.RegisterAgentResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("") + + params := url.Values{} + params.Add("agentVersion", fmt.Sprintf("%v", req.GetAgentVersion())) + params.Add("instanceIdToken", fmt.Sprintf("%v", req.GetInstanceIdToken())) + if req.GetOsArchitecture() != "" { + params.Add("osArchitecture", fmt.Sprintf("%v", req.GetOsArchitecture())) + } + if req.GetOsLongName() != "" { + params.Add("osLongName", fmt.Sprintf("%v", req.GetOsLongName())) + } + if req.GetOsShortName() != "" { + params.Add("osShortName", fmt.Sprintf("%v", req.GetOsShortName())) + } + if req.GetOsVersion() != "" { + params.Add("osVersion", fmt.Sprintf("%v", req.GetOsVersion())) + } + if req.GetSupportedCapabilities() != nil { + params.Add("supportedCapabilities", fmt.Sprintf("%v", req.GetSupportedCapabilities())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).RegisterAgent[0:len((*c.CallOptions).RegisterAgent):len((*c.CallOptions).RegisterAgent)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &agentendpointpb.RegisterAgentResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/osconfig/agentendpoint/apiv1beta/agent_endpoint_client_example_test.go b/osconfig/agentendpoint/apiv1beta/agent_endpoint_client_example_test.go index f356e91d3044..ead1a5d263ec 100644 --- a/osconfig/agentendpoint/apiv1beta/agent_endpoint_client_example_test.go +++ b/osconfig/agentendpoint/apiv1beta/agent_endpoint_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := agentendpoint.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_StartNextTask() { ctx := context.Background() c, err := agentendpoint.NewClient(ctx) diff --git a/osconfig/agentendpoint/apiv1beta/doc.go b/osconfig/agentendpoint/apiv1beta/doc.go index b710dc36da71..5acadb8b16ee 100644 --- a/osconfig/agentendpoint/apiv1beta/doc.go +++ b/osconfig/agentendpoint/apiv1beta/doc.go @@ -54,6 +54,8 @@ package agentendpoint // import "cloud.google.com/go/osconfig/agentendpoint/apiv import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -142,3 +144,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/osconfig/agentendpoint/apiv1beta/gapic_metadata.json b/osconfig/agentendpoint/apiv1beta/gapic_metadata.json index 3d302165c762..683fc312da33 100644 --- a/osconfig/agentendpoint/apiv1beta/gapic_metadata.json +++ b/osconfig/agentendpoint/apiv1beta/gapic_metadata.json @@ -41,6 +41,41 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "LookupEffectiveGuestPolicy": { + "methods": [ + "LookupEffectiveGuestPolicy" + ] + }, + "ReceiveTaskNotification": { + "methods": [ + "ReceiveTaskNotification" + ] + }, + "RegisterAgent": { + "methods": [ + "RegisterAgent" + ] + }, + "ReportTaskComplete": { + "methods": [ + "ReportTaskComplete" + ] + }, + "ReportTaskProgress": { + "methods": [ + "ReportTaskProgress" + ] + }, + "StartNextTask": { + "methods": [ + "StartNextTask" + ] + } + } } } } diff --git a/osconfig/apiv1alpha/doc.go b/osconfig/apiv1alpha/doc.go index c4915511db44..841789e18de2 100644 --- a/osconfig/apiv1alpha/doc.go +++ b/osconfig/apiv1alpha/doc.go @@ -77,6 +77,8 @@ package osconfig // import "cloud.google.com/go/osconfig/apiv1alpha" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -165,3 +167,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/osconfig/apiv1alpha/gapic_metadata.json b/osconfig/apiv1alpha/gapic_metadata.json index 8edd40fe520c..345a770a9ab9 100644 --- a/osconfig/apiv1alpha/gapic_metadata.json +++ b/osconfig/apiv1alpha/gapic_metadata.json @@ -81,6 +81,81 @@ ] } } + }, + "rest": { + "libraryClient": "OsConfigZonalClient", + "rpcs": { + "CreateOSPolicyAssignment": { + "methods": [ + "CreateOSPolicyAssignment" + ] + }, + "DeleteOSPolicyAssignment": { + "methods": [ + "DeleteOSPolicyAssignment" + ] + }, + "GetInstanceOSPoliciesCompliance": { + "methods": [ + "GetInstanceOSPoliciesCompliance" + ] + }, + "GetInventory": { + "methods": [ + "GetInventory" + ] + }, + "GetOSPolicyAssignment": { + "methods": [ + "GetOSPolicyAssignment" + ] + }, + "GetOSPolicyAssignmentReport": { + "methods": [ + "GetOSPolicyAssignmentReport" + ] + }, + "GetVulnerabilityReport": { + "methods": [ + "GetVulnerabilityReport" + ] + }, + "ListInstanceOSPoliciesCompliances": { + "methods": [ + "ListInstanceOSPoliciesCompliances" + ] + }, + "ListInventories": { + "methods": [ + "ListInventories" + ] + }, + "ListOSPolicyAssignmentReports": { + "methods": [ + "ListOSPolicyAssignmentReports" + ] + }, + "ListOSPolicyAssignmentRevisions": { + "methods": [ + "ListOSPolicyAssignmentRevisions" + ] + }, + "ListOSPolicyAssignments": { + "methods": [ + "ListOSPolicyAssignments" + ] + }, + "ListVulnerabilityReports": { + "methods": [ + "ListVulnerabilityReports" + ] + }, + "UpdateOSPolicyAssignment": { + "methods": [ + "UpdateOSPolicyAssignment" + ] + } + } } } } diff --git a/osconfig/apiv1alpha/os_config_zonal_client.go b/osconfig/apiv1alpha/os_config_zonal_client.go index 0d979c2208e9..14125965fca1 100644 --- a/osconfig/apiv1alpha/os_config_zonal_client.go +++ b/osconfig/apiv1alpha/os_config_zonal_client.go @@ -17,24 +17,30 @@ package osconfig import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" osconfigpb "google.golang.org/genproto/googleapis/cloud/osconfig/v1alpha" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -229,6 +235,151 @@ func defaultOsConfigZonalCallOptions() *OsConfigZonalCallOptions { } } +func defaultOsConfigZonalRESTCallOptions() *OsConfigZonalCallOptions { + return &OsConfigZonalCallOptions{ + CreateOSPolicyAssignment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateOSPolicyAssignment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetOSPolicyAssignment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListOSPolicyAssignments: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListOSPolicyAssignmentRevisions: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteOSPolicyAssignment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetInstanceOSPoliciesCompliance: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListInstanceOSPoliciesCompliances: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetOSPolicyAssignmentReport: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListOSPolicyAssignmentReports: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetInventory: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListInventories: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetVulnerabilityReport: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListVulnerabilityReports: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + } +} + // internalOsConfigZonalClient is an interface that defines the methods available from OS Config API. type internalOsConfigZonalClient interface { Close() error @@ -525,6 +676,92 @@ func (c *osConfigZonalGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type osConfigZonalRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing OsConfigZonalClient + CallOptions **OsConfigZonalCallOptions +} + +// NewOsConfigZonalRESTClient creates a new os config zonal service rest client. +// +// Zonal OS Config API +// +// The OS Config service is the server-side component that allows users to +// manage package installations and patch jobs for Compute Engine VM instances. +func NewOsConfigZonalRESTClient(ctx context.Context, opts ...option.ClientOption) (*OsConfigZonalClient, error) { + clientOpts := append(defaultOsConfigZonalRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultOsConfigZonalRESTCallOptions() + c := &osConfigZonalRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &OsConfigZonalClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultOsConfigZonalRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://osconfig.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://osconfig.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://osconfig.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *osConfigZonalRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *osConfigZonalRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *osConfigZonalRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *osConfigZonalGRPCClient) CreateOSPolicyAssignment(ctx context.Context, req *osconfigpb.CreateOSPolicyAssignmentRequest, opts ...gax.CallOption) (*CreateOSPolicyAssignmentOperation, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -977,92 +1214,1166 @@ func (c *osConfigZonalGRPCClient) ListVulnerabilityReports(ctx context.Context, return it } -// CreateOSPolicyAssignmentOperation manages a long-running operation from CreateOSPolicyAssignment. -type CreateOSPolicyAssignmentOperation struct { - lro *longrunning.Operation -} - -// CreateOSPolicyAssignmentOperation returns a new CreateOSPolicyAssignmentOperation from a given name. -// The name must be that of a previously created CreateOSPolicyAssignmentOperation, possibly from a different process. -func (c *osConfigZonalGRPCClient) CreateOSPolicyAssignmentOperation(name string) *CreateOSPolicyAssignmentOperation { - return &CreateOSPolicyAssignmentOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), - } -} - -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// CreateOSPolicyAssignment create an OS policy assignment. // -// See documentation of Poll for error-handling information. -func (op *CreateOSPolicyAssignmentOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*osconfigpb.OSPolicyAssignment, error) { - var resp osconfigpb.OSPolicyAssignment - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { - return nil, err - } - return &resp, nil -} - -// Poll fetches the latest state of the long-running operation. +// This method also creates the first revision of the OS policy assignment. // -// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// This method returns a long running operation (LRO) that contains the +// rollout details. The rollout can be cancelled by cancelling the LRO. // -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *CreateOSPolicyAssignmentOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*osconfigpb.OSPolicyAssignment, error) { - var resp osconfigpb.OSPolicyAssignment - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { +// For more information, see Method: +// projects.locations.osPolicyAssignments.operations.cancel (at https://cloud.google.com/compute/docs/osconfig/rest/v1alpha/projects.locations.osPolicyAssignments.operations/cancel). +func (c *osConfigZonalRESTClient) CreateOSPolicyAssignment(ctx context.Context, req *osconfigpb.CreateOSPolicyAssignmentRequest, opts ...gax.CallOption) (*CreateOSPolicyAssignmentOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetOsPolicyAssignment() + jsonReq, err := m.Marshal(body) + if err != nil { return nil, err } - if !op.Done() { - return nil, nil - } - return &resp, nil -} -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. -// If the metadata is not available, the returned metadata and error are both nil. -func (op *CreateOSPolicyAssignmentOperation) Metadata() (*osconfigpb.OSPolicyAssignmentOperationMetadata, error) { - var meta osconfigpb.OSPolicyAssignmentOperationMetadata - if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { - return nil, nil - } else if err != nil { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - return &meta, nil -} + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/osPolicyAssignments", req.GetParent()) -// Done reports whether the long-running operation has completed. -func (op *CreateOSPolicyAssignmentOperation) Done() bool { - return op.lro.Done() -} + params := url.Values{} + params.Add("osPolicyAssignmentId", fmt.Sprintf("%v", req.GetOsPolicyAssignmentId())) -// Name returns the name of the long-running operation. -// The name is assigned by the server and is unique within the service from which the operation is created. -func (op *CreateOSPolicyAssignmentOperation) Name() string { - return op.lro.Name() -} + baseUrl.RawQuery = params.Encode() -// DeleteOSPolicyAssignmentOperation manages a long-running operation from DeleteOSPolicyAssignment. -type DeleteOSPolicyAssignmentOperation struct { - lro *longrunning.Operation -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) -// DeleteOSPolicyAssignmentOperation returns a new DeleteOSPolicyAssignmentOperation from a given name. -// The name must be that of a previously created DeleteOSPolicyAssignmentOperation, possibly from a different process. -func (c *osConfigZonalGRPCClient) DeleteOSPolicyAssignmentOperation(name string) *DeleteOSPolicyAssignmentOperation { - return &DeleteOSPolicyAssignmentOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e } + + override := fmt.Sprintf("/v1alpha/%s", resp.GetName()) + return &CreateOSPolicyAssignmentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil } -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// UpdateOSPolicyAssignment update an existing OS policy assignment. // -// See documentation of Poll for error-handling information. +// This method creates a new revision of the OS policy assignment. +// +// This method returns a long running operation (LRO) that contains the +// rollout details. The rollout can be cancelled by cancelling the LRO. +// +// For more information, see Method: +// projects.locations.osPolicyAssignments.operations.cancel (at https://cloud.google.com/compute/docs/osconfig/rest/v1alpha/projects.locations.osPolicyAssignments.operations/cancel). +func (c *osConfigZonalRESTClient) UpdateOSPolicyAssignment(ctx context.Context, req *osconfigpb.UpdateOSPolicyAssignmentRequest, opts ...gax.CallOption) (*UpdateOSPolicyAssignmentOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetOsPolicyAssignment() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetOsPolicyAssignment().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "os_policy_assignment.name", url.QueryEscape(req.GetOsPolicyAssignment().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1alpha/%s", resp.GetName()) + return &UpdateOSPolicyAssignmentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// GetOSPolicyAssignment retrieve an existing OS policy assignment. +// +// This method always returns the latest revision. In order to retrieve a +// previous revision of the assignment, also provide the revision ID in the +// name parameter. +func (c *osConfigZonalRESTClient) GetOSPolicyAssignment(ctx context.Context, req *osconfigpb.GetOSPolicyAssignmentRequest, opts ...gax.CallOption) (*osconfigpb.OSPolicyAssignment, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOSPolicyAssignment[0:len((*c.CallOptions).GetOSPolicyAssignment):len((*c.CallOptions).GetOSPolicyAssignment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.OSPolicyAssignment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOSPolicyAssignments list the OS policy assignments under the parent resource. +// +// For each OS policy assignment, the latest revision is returned. +func (c *osConfigZonalRESTClient) ListOSPolicyAssignments(ctx context.Context, req *osconfigpb.ListOSPolicyAssignmentsRequest, opts ...gax.CallOption) *OSPolicyAssignmentIterator { + it := &OSPolicyAssignmentIterator{} + req = proto.Clone(req).(*osconfigpb.ListOSPolicyAssignmentsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*osconfigpb.OSPolicyAssignment, string, error) { + resp := &osconfigpb.ListOSPolicyAssignmentsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/osPolicyAssignments", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOsPolicyAssignments(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// ListOSPolicyAssignmentRevisions list the OS policy assignment revisions for a given OS policy assignment. +func (c *osConfigZonalRESTClient) ListOSPolicyAssignmentRevisions(ctx context.Context, req *osconfigpb.ListOSPolicyAssignmentRevisionsRequest, opts ...gax.CallOption) *OSPolicyAssignmentIterator { + it := &OSPolicyAssignmentIterator{} + req = proto.Clone(req).(*osconfigpb.ListOSPolicyAssignmentRevisionsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*osconfigpb.OSPolicyAssignment, string, error) { + resp := &osconfigpb.ListOSPolicyAssignmentRevisionsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v:listRevisions", req.GetName()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOsPolicyAssignments(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// DeleteOSPolicyAssignment delete the OS policy assignment. +// +// This method creates a new revision of the OS policy assignment. +// +// This method returns a long running operation (LRO) that contains the +// rollout details. The rollout can be cancelled by cancelling the LRO. +// +// If the LRO completes and is not cancelled, all revisions associated with +// the OS policy assignment are deleted. +// +// For more information, see Method: +// projects.locations.osPolicyAssignments.operations.cancel (at https://cloud.google.com/compute/docs/osconfig/rest/v1alpha/projects.locations.osPolicyAssignments.operations/cancel). +func (c *osConfigZonalRESTClient) DeleteOSPolicyAssignment(ctx context.Context, req *osconfigpb.DeleteOSPolicyAssignmentRequest, opts ...gax.CallOption) (*DeleteOSPolicyAssignmentOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1alpha/%s", resp.GetName()) + return &DeleteOSPolicyAssignmentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// GetInstanceOSPoliciesCompliance get OS policies compliance data for the specified Compute Engine VM +// instance. +// +// Deprecated: GetInstanceOSPoliciesCompliance may be removed in a future version. +func (c *osConfigZonalRESTClient) GetInstanceOSPoliciesCompliance(ctx context.Context, req *osconfigpb.GetInstanceOSPoliciesComplianceRequest, opts ...gax.CallOption) (*osconfigpb.InstanceOSPoliciesCompliance, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetInstanceOSPoliciesCompliance[0:len((*c.CallOptions).GetInstanceOSPoliciesCompliance):len((*c.CallOptions).GetInstanceOSPoliciesCompliance)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.InstanceOSPoliciesCompliance{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListInstanceOSPoliciesCompliances list OS policies compliance data for all Compute Engine VM instances in the +// specified zone. +// +// Deprecated: ListInstanceOSPoliciesCompliances may be removed in a future version. +func (c *osConfigZonalRESTClient) ListInstanceOSPoliciesCompliances(ctx context.Context, req *osconfigpb.ListInstanceOSPoliciesCompliancesRequest, opts ...gax.CallOption) *InstanceOSPoliciesComplianceIterator { + it := &InstanceOSPoliciesComplianceIterator{} + req = proto.Clone(req).(*osconfigpb.ListInstanceOSPoliciesCompliancesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*osconfigpb.InstanceOSPoliciesCompliance, string, error) { + resp := &osconfigpb.ListInstanceOSPoliciesCompliancesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/instanceOSPoliciesCompliances", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetInstanceOsPoliciesCompliances(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetOSPolicyAssignmentReport get the OS policy asssignment report for the specified Compute Engine VM +// instance. +func (c *osConfigZonalRESTClient) GetOSPolicyAssignmentReport(ctx context.Context, req *osconfigpb.GetOSPolicyAssignmentReportRequest, opts ...gax.CallOption) (*osconfigpb.OSPolicyAssignmentReport, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOSPolicyAssignmentReport[0:len((*c.CallOptions).GetOSPolicyAssignmentReport):len((*c.CallOptions).GetOSPolicyAssignmentReport)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.OSPolicyAssignmentReport{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListOSPolicyAssignmentReports list OS policy asssignment reports for all Compute Engine VM instances in +// the specified zone. +func (c *osConfigZonalRESTClient) ListOSPolicyAssignmentReports(ctx context.Context, req *osconfigpb.ListOSPolicyAssignmentReportsRequest, opts ...gax.CallOption) *OSPolicyAssignmentReportIterator { + it := &OSPolicyAssignmentReportIterator{} + req = proto.Clone(req).(*osconfigpb.ListOSPolicyAssignmentReportsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*osconfigpb.OSPolicyAssignmentReport, string, error) { + resp := &osconfigpb.ListOSPolicyAssignmentReportsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/reports", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetOsPolicyAssignmentReports(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetInventory get inventory data for the specified VM instance. If the VM has no +// associated inventory, the message NOT_FOUND is returned. +func (c *osConfigZonalRESTClient) GetInventory(ctx context.Context, req *osconfigpb.GetInventoryRequest, opts ...gax.CallOption) (*osconfigpb.Inventory, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + params := url.Values{} + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetInventory[0:len((*c.CallOptions).GetInventory):len((*c.CallOptions).GetInventory)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.Inventory{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListInventories list inventory data for all VM instances in the specified zone. +func (c *osConfigZonalRESTClient) ListInventories(ctx context.Context, req *osconfigpb.ListInventoriesRequest, opts ...gax.CallOption) *InventoryIterator { + it := &InventoryIterator{} + req = proto.Clone(req).(*osconfigpb.ListInventoriesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*osconfigpb.Inventory, string, error) { + resp := &osconfigpb.ListInventoriesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/inventories", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetInventories(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetVulnerabilityReport gets the vulnerability report for the specified VM instance. Only VMs with +// inventory data have vulnerability reports associated with them. +func (c *osConfigZonalRESTClient) GetVulnerabilityReport(ctx context.Context, req *osconfigpb.GetVulnerabilityReportRequest, opts ...gax.CallOption) (*osconfigpb.VulnerabilityReport, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetVulnerabilityReport[0:len((*c.CallOptions).GetVulnerabilityReport):len((*c.CallOptions).GetVulnerabilityReport)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.VulnerabilityReport{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListVulnerabilityReports list vulnerability reports for all VM instances in the specified zone. +func (c *osConfigZonalRESTClient) ListVulnerabilityReports(ctx context.Context, req *osconfigpb.ListVulnerabilityReportsRequest, opts ...gax.CallOption) *VulnerabilityReportIterator { + it := &VulnerabilityReportIterator{} + req = proto.Clone(req).(*osconfigpb.ListVulnerabilityReportsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*osconfigpb.VulnerabilityReport, string, error) { + resp := &osconfigpb.ListVulnerabilityReportsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1alpha/%v/vulnerabilityReports", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetVulnerabilityReports(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CreateOSPolicyAssignmentOperation manages a long-running operation from CreateOSPolicyAssignment. +type CreateOSPolicyAssignmentOperation struct { + lro *longrunning.Operation + pollPath string +} + +// CreateOSPolicyAssignmentOperation returns a new CreateOSPolicyAssignmentOperation from a given name. +// The name must be that of a previously created CreateOSPolicyAssignmentOperation, possibly from a different process. +func (c *osConfigZonalGRPCClient) CreateOSPolicyAssignmentOperation(name string) *CreateOSPolicyAssignmentOperation { + return &CreateOSPolicyAssignmentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// CreateOSPolicyAssignmentOperation returns a new CreateOSPolicyAssignmentOperation from a given name. +// The name must be that of a previously created CreateOSPolicyAssignmentOperation, possibly from a different process. +func (c *osConfigZonalRESTClient) CreateOSPolicyAssignmentOperation(name string) *CreateOSPolicyAssignmentOperation { + override := fmt.Sprintf("/v1alpha/%s", name) + return &CreateOSPolicyAssignmentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateOSPolicyAssignmentOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*osconfigpb.OSPolicyAssignment, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp osconfigpb.OSPolicyAssignment + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateOSPolicyAssignmentOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*osconfigpb.OSPolicyAssignment, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp osconfigpb.OSPolicyAssignment + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateOSPolicyAssignmentOperation) Metadata() (*osconfigpb.OSPolicyAssignmentOperationMetadata, error) { + var meta osconfigpb.OSPolicyAssignmentOperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateOSPolicyAssignmentOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *CreateOSPolicyAssignmentOperation) Name() string { + return op.lro.Name() +} + +// DeleteOSPolicyAssignmentOperation manages a long-running operation from DeleteOSPolicyAssignment. +type DeleteOSPolicyAssignmentOperation struct { + lro *longrunning.Operation + pollPath string +} + +// DeleteOSPolicyAssignmentOperation returns a new DeleteOSPolicyAssignmentOperation from a given name. +// The name must be that of a previously created DeleteOSPolicyAssignmentOperation, possibly from a different process. +func (c *osConfigZonalGRPCClient) DeleteOSPolicyAssignmentOperation(name string) *DeleteOSPolicyAssignmentOperation { + return &DeleteOSPolicyAssignmentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// DeleteOSPolicyAssignmentOperation returns a new DeleteOSPolicyAssignmentOperation from a given name. +// The name must be that of a previously created DeleteOSPolicyAssignmentOperation, possibly from a different process. +func (c *osConfigZonalRESTClient) DeleteOSPolicyAssignmentOperation(name string) *DeleteOSPolicyAssignmentOperation { + override := fmt.Sprintf("/v1alpha/%s", name) + return &DeleteOSPolicyAssignmentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. func (op *DeleteOSPolicyAssignmentOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -1076,6 +2387,7 @@ func (op *DeleteOSPolicyAssignmentOperation) Wait(ctx context.Context, opts ...g // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeleteOSPolicyAssignmentOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -1106,7 +2418,8 @@ func (op *DeleteOSPolicyAssignmentOperation) Name() string { // UpdateOSPolicyAssignmentOperation manages a long-running operation from UpdateOSPolicyAssignment. type UpdateOSPolicyAssignmentOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UpdateOSPolicyAssignmentOperation returns a new UpdateOSPolicyAssignmentOperation from a given name. @@ -1117,10 +2430,21 @@ func (c *osConfigZonalGRPCClient) UpdateOSPolicyAssignmentOperation(name string) } } +// UpdateOSPolicyAssignmentOperation returns a new UpdateOSPolicyAssignmentOperation from a given name. +// The name must be that of a previously created UpdateOSPolicyAssignmentOperation, possibly from a different process. +func (c *osConfigZonalRESTClient) UpdateOSPolicyAssignmentOperation(name string) *UpdateOSPolicyAssignmentOperation { + override := fmt.Sprintf("/v1alpha/%s", name) + return &UpdateOSPolicyAssignmentOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UpdateOSPolicyAssignmentOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*osconfigpb.OSPolicyAssignment, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp osconfigpb.OSPolicyAssignment if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1138,6 +2462,7 @@ func (op *UpdateOSPolicyAssignmentOperation) Wait(ctx context.Context, opts ...g // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UpdateOSPolicyAssignmentOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*osconfigpb.OSPolicyAssignment, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp osconfigpb.OSPolicyAssignment if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/osconfig/apiv1alpha/os_config_zonal_client_example_test.go b/osconfig/apiv1alpha/os_config_zonal_client_example_test.go index f66e58cc4e33..d736a540bd0c 100644 --- a/osconfig/apiv1alpha/os_config_zonal_client_example_test.go +++ b/osconfig/apiv1alpha/os_config_zonal_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewOsConfigZonalClient() { _ = c } +func ExampleNewOsConfigZonalRESTClient() { + ctx := context.Background() + c, err := osconfig.NewOsConfigZonalRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleOsConfigZonalClient_CreateOSPolicyAssignment() { ctx := context.Background() c, err := osconfig.NewOsConfigZonalClient(ctx) diff --git a/osconfig/apiv1beta/doc.go b/osconfig/apiv1beta/doc.go index 1b4af32457ac..e230090af59a 100644 --- a/osconfig/apiv1beta/doc.go +++ b/osconfig/apiv1beta/doc.go @@ -72,6 +72,8 @@ package osconfig // import "cloud.google.com/go/osconfig/apiv1beta" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -160,3 +162,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/osconfig/apiv1beta/gapic_metadata.json b/osconfig/apiv1beta/gapic_metadata.json index 07bfa52f329e..dce2de4793ac 100644 --- a/osconfig/apiv1beta/gapic_metadata.json +++ b/osconfig/apiv1beta/gapic_metadata.json @@ -101,6 +101,101 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "CancelPatchJob": { + "methods": [ + "CancelPatchJob" + ] + }, + "CreateGuestPolicy": { + "methods": [ + "CreateGuestPolicy" + ] + }, + "CreatePatchDeployment": { + "methods": [ + "CreatePatchDeployment" + ] + }, + "DeleteGuestPolicy": { + "methods": [ + "DeleteGuestPolicy" + ] + }, + "DeletePatchDeployment": { + "methods": [ + "DeletePatchDeployment" + ] + }, + "ExecutePatchJob": { + "methods": [ + "ExecutePatchJob" + ] + }, + "GetGuestPolicy": { + "methods": [ + "GetGuestPolicy" + ] + }, + "GetPatchDeployment": { + "methods": [ + "GetPatchDeployment" + ] + }, + "GetPatchJob": { + "methods": [ + "GetPatchJob" + ] + }, + "ListGuestPolicies": { + "methods": [ + "ListGuestPolicies" + ] + }, + "ListPatchDeployments": { + "methods": [ + "ListPatchDeployments" + ] + }, + "ListPatchJobInstanceDetails": { + "methods": [ + "ListPatchJobInstanceDetails" + ] + }, + "ListPatchJobs": { + "methods": [ + "ListPatchJobs" + ] + }, + "LookupEffectiveGuestPolicy": { + "methods": [ + "LookupEffectiveGuestPolicy" + ] + }, + "PausePatchDeployment": { + "methods": [ + "PausePatchDeployment" + ] + }, + "ResumePatchDeployment": { + "methods": [ + "ResumePatchDeployment" + ] + }, + "UpdateGuestPolicy": { + "methods": [ + "UpdateGuestPolicy" + ] + }, + "UpdatePatchDeployment": { + "methods": [ + "UpdatePatchDeployment" + ] + } + } } } } diff --git a/osconfig/apiv1beta/os_config_client.go b/osconfig/apiv1beta/os_config_client.go index a467ef0d014e..8dd90bdead42 100644 --- a/osconfig/apiv1beta/os_config_client.go +++ b/osconfig/apiv1beta/os_config_client.go @@ -17,21 +17,27 @@ package osconfig import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" osconfigpb "google.golang.org/genproto/googleapis/cloud/osconfig/v1beta" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -274,6 +280,191 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + ExecutePatchJob: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetPatchJob: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CancelPatchJob: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListPatchJobs: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListPatchJobInstanceDetails: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreatePatchDeployment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetPatchDeployment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListPatchDeployments: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeletePatchDeployment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdatePatchDeployment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + PausePatchDeployment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ResumePatchDeployment: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + CreateGuestPolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + GetGuestPolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + ListGuestPolicies: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + UpdateGuestPolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + DeleteGuestPolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + LookupEffectiveGuestPolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable) + }), + }, + } +} + // internalClient is an interface that defines the methods available from OS Config API. type internalClient interface { Close() error @@ -514,6 +705,77 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new os config service rest client. +// +// OS Config API +// +// The OS Config service is a server-side component that you can use to +// manage package installations and patch jobs for virtual machine instances. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://osconfig.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://osconfig.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://osconfig.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) ExecutePatchJob(ctx context.Context, req *osconfigpb.ExecutePatchJobRequest, opts ...gax.CallOption) (*osconfigpb.PatchJob, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 60000*time.Millisecond) @@ -994,6 +1256,1153 @@ func (c *gRPCClient) LookupEffectiveGuestPolicy(ctx context.Context, req *osconf return resp, nil } +// ExecutePatchJob patch VM instances by creating and running a patch job. +func (c *restClient) ExecutePatchJob(ctx context.Context, req *osconfigpb.ExecutePatchJobRequest, opts ...gax.CallOption) (*osconfigpb.PatchJob, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/patchJobs:execute", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ExecutePatchJob[0:len((*c.CallOptions).ExecutePatchJob):len((*c.CallOptions).ExecutePatchJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.PatchJob{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetPatchJob get the patch job. This can be used to track the progress of an +// ongoing patch job or review the details of completed jobs. +func (c *restClient) GetPatchJob(ctx context.Context, req *osconfigpb.GetPatchJobRequest, opts ...gax.CallOption) (*osconfigpb.PatchJob, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetPatchJob[0:len((*c.CallOptions).GetPatchJob):len((*c.CallOptions).GetPatchJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.PatchJob{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CancelPatchJob cancel a patch job. The patch job must be active. Canceled patch jobs +// cannot be restarted. +func (c *restClient) CancelPatchJob(ctx context.Context, req *osconfigpb.CancelPatchJobRequest, opts ...gax.CallOption) (*osconfigpb.PatchJob, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CancelPatchJob[0:len((*c.CallOptions).CancelPatchJob):len((*c.CallOptions).CancelPatchJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.PatchJob{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListPatchJobs get a list of patch jobs. +func (c *restClient) ListPatchJobs(ctx context.Context, req *osconfigpb.ListPatchJobsRequest, opts ...gax.CallOption) *PatchJobIterator { + it := &PatchJobIterator{} + req = proto.Clone(req).(*osconfigpb.ListPatchJobsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*osconfigpb.PatchJob, string, error) { + resp := &osconfigpb.ListPatchJobsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/patchJobs", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetPatchJobs(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// ListPatchJobInstanceDetails get a list of instance details for a given patch job. +func (c *restClient) ListPatchJobInstanceDetails(ctx context.Context, req *osconfigpb.ListPatchJobInstanceDetailsRequest, opts ...gax.CallOption) *PatchJobInstanceDetailsIterator { + it := &PatchJobInstanceDetailsIterator{} + req = proto.Clone(req).(*osconfigpb.ListPatchJobInstanceDetailsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*osconfigpb.PatchJobInstanceDetails, string, error) { + resp := &osconfigpb.ListPatchJobInstanceDetailsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/instanceDetails", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetPatchJobInstanceDetails(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CreatePatchDeployment create an OS Config patch deployment. +func (c *restClient) CreatePatchDeployment(ctx context.Context, req *osconfigpb.CreatePatchDeploymentRequest, opts ...gax.CallOption) (*osconfigpb.PatchDeployment, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetPatchDeployment() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/patchDeployments", req.GetParent()) + + params := url.Values{} + params.Add("patchDeploymentId", fmt.Sprintf("%v", req.GetPatchDeploymentId())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreatePatchDeployment[0:len((*c.CallOptions).CreatePatchDeployment):len((*c.CallOptions).CreatePatchDeployment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.PatchDeployment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetPatchDeployment get an OS Config patch deployment. +func (c *restClient) GetPatchDeployment(ctx context.Context, req *osconfigpb.GetPatchDeploymentRequest, opts ...gax.CallOption) (*osconfigpb.PatchDeployment, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetPatchDeployment[0:len((*c.CallOptions).GetPatchDeployment):len((*c.CallOptions).GetPatchDeployment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.PatchDeployment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListPatchDeployments get a page of OS Config patch deployments. +func (c *restClient) ListPatchDeployments(ctx context.Context, req *osconfigpb.ListPatchDeploymentsRequest, opts ...gax.CallOption) *PatchDeploymentIterator { + it := &PatchDeploymentIterator{} + req = proto.Clone(req).(*osconfigpb.ListPatchDeploymentsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*osconfigpb.PatchDeployment, string, error) { + resp := &osconfigpb.ListPatchDeploymentsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/patchDeployments", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetPatchDeployments(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// DeletePatchDeployment delete an OS Config patch deployment. +func (c *restClient) DeletePatchDeployment(ctx context.Context, req *osconfigpb.DeletePatchDeploymentRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// UpdatePatchDeployment update an OS Config patch deployment. +func (c *restClient) UpdatePatchDeployment(ctx context.Context, req *osconfigpb.UpdatePatchDeploymentRequest, opts ...gax.CallOption) (*osconfigpb.PatchDeployment, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetPatchDeployment() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetPatchDeployment().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "patch_deployment.name", url.QueryEscape(req.GetPatchDeployment().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdatePatchDeployment[0:len((*c.CallOptions).UpdatePatchDeployment):len((*c.CallOptions).UpdatePatchDeployment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.PatchDeployment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// PausePatchDeployment change state of patch deployment to “PAUSED”. +// Patch deployment in paused state doesn’t generate patch jobs. +func (c *restClient) PausePatchDeployment(ctx context.Context, req *osconfigpb.PausePatchDeploymentRequest, opts ...gax.CallOption) (*osconfigpb.PatchDeployment, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v:pause", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).PausePatchDeployment[0:len((*c.CallOptions).PausePatchDeployment):len((*c.CallOptions).PausePatchDeployment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.PatchDeployment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ResumePatchDeployment change state of patch deployment back to “ACTIVE”. +// Patch deployment in active state continues to generate patch jobs. +func (c *restClient) ResumePatchDeployment(ctx context.Context, req *osconfigpb.ResumePatchDeploymentRequest, opts ...gax.CallOption) (*osconfigpb.PatchDeployment, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v:resume", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ResumePatchDeployment[0:len((*c.CallOptions).ResumePatchDeployment):len((*c.CallOptions).ResumePatchDeployment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.PatchDeployment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateGuestPolicy create an OS Config guest policy. +func (c *restClient) CreateGuestPolicy(ctx context.Context, req *osconfigpb.CreateGuestPolicyRequest, opts ...gax.CallOption) (*osconfigpb.GuestPolicy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetGuestPolicy() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/guestPolicies", req.GetParent()) + + params := url.Values{} + params.Add("guestPolicyId", fmt.Sprintf("%v", req.GetGuestPolicyId())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateGuestPolicy[0:len((*c.CallOptions).CreateGuestPolicy):len((*c.CallOptions).CreateGuestPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.GuestPolicy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetGuestPolicy get an OS Config guest policy. +func (c *restClient) GetGuestPolicy(ctx context.Context, req *osconfigpb.GetGuestPolicyRequest, opts ...gax.CallOption) (*osconfigpb.GuestPolicy, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetGuestPolicy[0:len((*c.CallOptions).GetGuestPolicy):len((*c.CallOptions).GetGuestPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.GuestPolicy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListGuestPolicies get a page of OS Config guest policies. +func (c *restClient) ListGuestPolicies(ctx context.Context, req *osconfigpb.ListGuestPoliciesRequest, opts ...gax.CallOption) *GuestPolicyIterator { + it := &GuestPolicyIterator{} + req = proto.Clone(req).(*osconfigpb.ListGuestPoliciesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*osconfigpb.GuestPolicy, string, error) { + resp := &osconfigpb.ListGuestPoliciesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/guestPolicies", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetGuestPolicies(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// UpdateGuestPolicy update an OS Config guest policy. +func (c *restClient) UpdateGuestPolicy(ctx context.Context, req *osconfigpb.UpdateGuestPolicyRequest, opts ...gax.CallOption) (*osconfigpb.GuestPolicy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetGuestPolicy() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetGuestPolicy().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "guest_policy.name", url.QueryEscape(req.GetGuestPolicy().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateGuestPolicy[0:len((*c.CallOptions).UpdateGuestPolicy):len((*c.CallOptions).UpdateGuestPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.GuestPolicy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteGuestPolicy delete an OS Config guest policy. +func (c *restClient) DeleteGuestPolicy(ctx context.Context, req *osconfigpb.DeleteGuestPolicyRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// LookupEffectiveGuestPolicy lookup the effective guest policy that applies to a VM instance. This +// lookup merges all policies that are assigned to the instance ancestry. +func (c *restClient) LookupEffectiveGuestPolicy(ctx context.Context, req *osconfigpb.LookupEffectiveGuestPolicyRequest, opts ...gax.CallOption) (*osconfigpb.EffectiveGuestPolicy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v:lookupEffectiveGuestPolicy", req.GetInstance()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "instance", url.QueryEscape(req.GetInstance()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).LookupEffectiveGuestPolicy[0:len((*c.CallOptions).LookupEffectiveGuestPolicy):len((*c.CallOptions).LookupEffectiveGuestPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osconfigpb.EffectiveGuestPolicy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // GuestPolicyIterator manages a stream of *osconfigpb.GuestPolicy. type GuestPolicyIterator struct { items []*osconfigpb.GuestPolicy diff --git a/osconfig/apiv1beta/os_config_client_example_test.go b/osconfig/apiv1beta/os_config_client_example_test.go index f5f3713a3b4e..46c2bad1c901 100644 --- a/osconfig/apiv1beta/os_config_client_example_test.go +++ b/osconfig/apiv1beta/os_config_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := osconfig.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_ExecutePatchJob() { ctx := context.Background() c, err := osconfig.NewClient(ctx) diff --git a/oslogin/apiv1beta/doc.go b/oslogin/apiv1beta/doc.go index d470ccc9448c..4e5e48527a72 100644 --- a/oslogin/apiv1beta/doc.go +++ b/oslogin/apiv1beta/doc.go @@ -70,6 +70,8 @@ package oslogin // import "cloud.google.com/go/oslogin/apiv1beta" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -161,3 +163,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/oslogin/apiv1beta/gapic_metadata.json b/oslogin/apiv1beta/gapic_metadata.json index ddd46bd05909..31d21903c27c 100644 --- a/oslogin/apiv1beta/gapic_metadata.json +++ b/oslogin/apiv1beta/gapic_metadata.json @@ -41,6 +41,41 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "DeletePosixAccount": { + "methods": [ + "DeletePosixAccount" + ] + }, + "DeleteSshPublicKey": { + "methods": [ + "DeleteSshPublicKey" + ] + }, + "GetLoginProfile": { + "methods": [ + "GetLoginProfile" + ] + }, + "GetSshPublicKey": { + "methods": [ + "GetSshPublicKey" + ] + }, + "ImportSshPublicKey": { + "methods": [ + "ImportSshPublicKey" + ] + }, + "UpdateSshPublicKey": { + "methods": [ + "UpdateSshPublicKey" + ] + } + } } } } diff --git a/oslogin/apiv1beta/os_login_client.go b/oslogin/apiv1beta/os_login_client.go index 2a9f657ec8d7..ab4422236197 100644 --- a/oslogin/apiv1beta/os_login_client.go +++ b/oslogin/apiv1beta/os_login_client.go @@ -17,21 +17,27 @@ package oslogin import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" commonpb "google.golang.org/genproto/googleapis/cloud/oslogin/common" osloginpb "google.golang.org/genproto/googleapis/cloud/oslogin/v1beta" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newClientHook clientHook @@ -135,6 +141,77 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + DeletePosixAccount: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + DeleteSshPublicKey: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + GetLoginProfile: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + GetSshPublicKey: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + ImportSshPublicKey: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + UpdateSshPublicKey: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + } +} + // internalClient is an interface that defines the methods available from Cloud OS Login API. type internalClient interface { Close() error @@ -302,6 +379,77 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new os login service rest client. +// +// Cloud OS Login API +// +// The Cloud OS Login API allows you to manage users and their associated SSH +// public keys for logging into virtual machines on Google Cloud Platform. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://oslogin.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://oslogin.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://oslogin.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) DeletePosixAccount(ctx context.Context, req *osloginpb.DeletePosixAccountRequest, opts ...gax.CallOption) error { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 10000*time.Millisecond) @@ -425,3 +573,327 @@ func (c *gRPCClient) UpdateSshPublicKey(ctx context.Context, req *osloginpb.Upda } return resp, nil } + +// DeletePosixAccount deletes a POSIX account. +func (c *restClient) DeletePosixAccount(ctx context.Context, req *osloginpb.DeletePosixAccountRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// DeleteSshPublicKey deletes an SSH public key. +func (c *restClient) DeleteSshPublicKey(ctx context.Context, req *osloginpb.DeleteSshPublicKeyRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetLoginProfile retrieves the profile information used for logging in to a virtual machine +// on Google Compute Engine. +func (c *restClient) GetLoginProfile(ctx context.Context, req *osloginpb.GetLoginProfileRequest, opts ...gax.CallOption) (*osloginpb.LoginProfile, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/loginProfile", req.GetName()) + + params := url.Values{} + if req.GetProjectId() != "" { + params.Add("projectId", fmt.Sprintf("%v", req.GetProjectId())) + } + if req.GetSystemId() != "" { + params.Add("systemId", fmt.Sprintf("%v", req.GetSystemId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetLoginProfile[0:len((*c.CallOptions).GetLoginProfile):len((*c.CallOptions).GetLoginProfile)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osloginpb.LoginProfile{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetSshPublicKey retrieves an SSH public key. +func (c *restClient) GetSshPublicKey(ctx context.Context, req *osloginpb.GetSshPublicKeyRequest, opts ...gax.CallOption) (*commonpb.SshPublicKey, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetSshPublicKey[0:len((*c.CallOptions).GetSshPublicKey):len((*c.CallOptions).GetSshPublicKey)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &commonpb.SshPublicKey{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ImportSshPublicKey adds an SSH public key and returns the profile information. Default POSIX +// account information is set when no username and UID exist as part of the +// login profile. +func (c *restClient) ImportSshPublicKey(ctx context.Context, req *osloginpb.ImportSshPublicKeyRequest, opts ...gax.CallOption) (*osloginpb.ImportSshPublicKeyResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetSshPublicKey() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v:importSshPublicKey", req.GetParent()) + + params := url.Values{} + if req.GetProjectId() != "" { + params.Add("projectId", fmt.Sprintf("%v", req.GetProjectId())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ImportSshPublicKey[0:len((*c.CallOptions).ImportSshPublicKey):len((*c.CallOptions).ImportSshPublicKey)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &osloginpb.ImportSshPublicKeyResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateSshPublicKey updates an SSH public key and returns the profile information. This method +// supports patch semantics. +func (c *restClient) UpdateSshPublicKey(ctx context.Context, req *osloginpb.UpdateSshPublicKeyRequest, opts ...gax.CallOption) (*commonpb.SshPublicKey, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetSshPublicKey() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateSshPublicKey[0:len((*c.CallOptions).UpdateSshPublicKey):len((*c.CallOptions).UpdateSshPublicKey)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &commonpb.SshPublicKey{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/oslogin/apiv1beta/os_login_client_example_test.go b/oslogin/apiv1beta/os_login_client_example_test.go index 4523f208a1c7..e8ac42ef9ba4 100644 --- a/oslogin/apiv1beta/os_login_client_example_test.go +++ b/oslogin/apiv1beta/os_login_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := oslogin.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_DeletePosixAccount() { ctx := context.Background() c, err := oslogin.NewClient(ctx) diff --git a/oslogin/go.mod b/oslogin/go.mod index 38390827aa76..6f771032ca03 100644 --- a/oslogin/go.mod +++ b/oslogin/go.mod @@ -8,4 +8,5 @@ require ( google.golang.org/api v0.84.0 google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90 google.golang.org/grpc v1.47.0 + google.golang.org/protobuf v1.28.0 ) diff --git a/phishingprotection/apiv1beta1/doc.go b/phishingprotection/apiv1beta1/doc.go index ec500ea77e18..e71e74fb6d93 100644 --- a/phishingprotection/apiv1beta1/doc.go +++ b/phishingprotection/apiv1beta1/doc.go @@ -69,6 +69,8 @@ package phishingprotection // import "cloud.google.com/go/phishingprotection/api import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -157,3 +159,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/phishingprotection/apiv1beta1/gapic_metadata.json b/phishingprotection/apiv1beta1/gapic_metadata.json index fafe97d9d874..0fc266f8a3d2 100644 --- a/phishingprotection/apiv1beta1/gapic_metadata.json +++ b/phishingprotection/apiv1beta1/gapic_metadata.json @@ -16,6 +16,16 @@ ] } } + }, + "rest": { + "libraryClient": "PhishingProtectionServiceV1Beta1Client", + "rpcs": { + "ReportPhishing": { + "methods": [ + "ReportPhishing" + ] + } + } } } } diff --git a/phishingprotection/apiv1beta1/phishing_protection_service_v1_beta1_client.go b/phishingprotection/apiv1beta1/phishing_protection_service_v1_beta1_client.go index 179661776e4a..60cf1013cbbc 100644 --- a/phishingprotection/apiv1beta1/phishing_protection_service_v1_beta1_client.go +++ b/phishingprotection/apiv1beta1/phishing_protection_service_v1_beta1_client.go @@ -17,19 +17,25 @@ package phishingprotection import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" phishingprotectionpb "google.golang.org/genproto/googleapis/cloud/phishingprotection/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newPhishingProtectionServiceV1Beta1ClientHook clientHook @@ -57,6 +63,12 @@ func defaultPhishingProtectionServiceV1Beta1CallOptions() *PhishingProtectionSer } } +func defaultPhishingProtectionServiceV1Beta1RESTCallOptions() *PhishingProtectionServiceV1Beta1CallOptions { + return &PhishingProtectionServiceV1Beta1CallOptions{ + ReportPhishing: []gax.CallOption{}, + } +} + // internalPhishingProtectionServiceV1Beta1Client is an interface that defines the methods available from Phishing Protection API. type internalPhishingProtectionServiceV1Beta1Client interface { Close() error @@ -190,6 +202,74 @@ func (c *phishingProtectionServiceV1Beta1GRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type phishingProtectionServiceV1Beta1RESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing PhishingProtectionServiceV1Beta1Client + CallOptions **PhishingProtectionServiceV1Beta1CallOptions +} + +// NewPhishingProtectionServiceV1Beta1RESTClient creates a new phishing protection service v1 beta1 rest client. +// +// Service to report phishing URIs. +func NewPhishingProtectionServiceV1Beta1RESTClient(ctx context.Context, opts ...option.ClientOption) (*PhishingProtectionServiceV1Beta1Client, error) { + clientOpts := append(defaultPhishingProtectionServiceV1Beta1RESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultPhishingProtectionServiceV1Beta1RESTCallOptions() + c := &phishingProtectionServiceV1Beta1RESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &PhishingProtectionServiceV1Beta1Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultPhishingProtectionServiceV1Beta1RESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://phishingprotection.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://phishingprotection.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://phishingprotection.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *phishingProtectionServiceV1Beta1RESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *phishingProtectionServiceV1Beta1RESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *phishingProtectionServiceV1Beta1RESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *phishingProtectionServiceV1Beta1GRPCClient) ReportPhishing(ctx context.Context, req *phishingprotectionpb.ReportPhishingRequest, opts ...gax.CallOption) (*phishingprotectionpb.ReportPhishingResponse, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) @@ -211,3 +291,68 @@ func (c *phishingProtectionServiceV1Beta1GRPCClient) ReportPhishing(ctx context. } return resp, nil } + +// ReportPhishing reports a URI suspected of containing phishing content to be reviewed. Once +// the report review is complete, its result can be found in the Cloud +// Security Command Center findings dashboard for Phishing Protection. If the +// result verifies the existence of malicious phishing content, the site will +// be added the to Google’s Social Engineering +// lists (at https://support.google.com/webmasters/answer/6350487/) in order to +// protect users that could get exposed to this threat in the future. +func (c *phishingProtectionServiceV1Beta1RESTClient) ReportPhishing(ctx context.Context, req *phishingprotectionpb.ReportPhishingRequest, opts ...gax.CallOption) (*phishingprotectionpb.ReportPhishingResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/phishing:report", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ReportPhishing[0:len((*c.CallOptions).ReportPhishing):len((*c.CallOptions).ReportPhishing)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &phishingprotectionpb.ReportPhishingResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/phishingprotection/apiv1beta1/phishing_protection_service_v1_beta1_client_example_test.go b/phishingprotection/apiv1beta1/phishing_protection_service_v1_beta1_client_example_test.go index e16036bfd172..9161ab6cf6f0 100644 --- a/phishingprotection/apiv1beta1/phishing_protection_service_v1_beta1_client_example_test.go +++ b/phishingprotection/apiv1beta1/phishing_protection_service_v1_beta1_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewPhishingProtectionServiceV1Beta1Client() { _ = c } +func ExampleNewPhishingProtectionServiceV1Beta1RESTClient() { + ctx := context.Background() + c, err := phishingprotection.NewPhishingProtectionServiceV1Beta1RESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExamplePhishingProtectionServiceV1Beta1Client_ReportPhishing() { ctx := context.Background() c, err := phishingprotection.NewPhishingProtectionServiceV1Beta1Client(ctx) diff --git a/phishingprotection/go.mod b/phishingprotection/go.mod index 7791fbc5f5e1..ad58682a9e58 100644 --- a/phishingprotection/go.mod +++ b/phishingprotection/go.mod @@ -9,4 +9,5 @@ require ( google.golang.org/api v0.84.0 google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad google.golang.org/grpc v1.47.0 + google.golang.org/protobuf v1.28.0 ) diff --git a/privatecatalog/apiv1beta1/doc.go b/privatecatalog/apiv1beta1/doc.go index 20572e1f76d9..bd58ec40edf6 100644 --- a/privatecatalog/apiv1beta1/doc.go +++ b/privatecatalog/apiv1beta1/doc.go @@ -78,6 +78,8 @@ package privatecatalog // import "cloud.google.com/go/privatecatalog/apiv1beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -166,3 +168,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/privatecatalog/apiv1beta1/gapic_metadata.json b/privatecatalog/apiv1beta1/gapic_metadata.json index a549a3afcb23..b884968a8646 100644 --- a/privatecatalog/apiv1beta1/gapic_metadata.json +++ b/privatecatalog/apiv1beta1/gapic_metadata.json @@ -26,6 +26,26 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "SearchCatalogs": { + "methods": [ + "SearchCatalogs" + ] + }, + "SearchProducts": { + "methods": [ + "SearchProducts" + ] + }, + "SearchVersions": { + "methods": [ + "SearchVersions" + ] + } + } } } } diff --git a/privatecatalog/apiv1beta1/private_catalog_client.go b/privatecatalog/apiv1beta1/private_catalog_client.go index 6adaf3171980..5c2b5fee9f97 100644 --- a/privatecatalog/apiv1beta1/private_catalog_client.go +++ b/privatecatalog/apiv1beta1/private_catalog_client.go @@ -19,17 +19,22 @@ package privatecatalog import ( "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" privatecatalogpb "google.golang.org/genproto/googleapis/cloud/privatecatalog/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -62,6 +67,14 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + SearchCatalogs: []gax.CallOption{}, + SearchProducts: []gax.CallOption{}, + SearchVersions: []gax.CallOption{}, + } +} + // internalClient is an interface that defines the methods available from Cloud Private Catalog API. type internalClient interface { Close() error @@ -244,6 +257,94 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new private catalog rest client. +// +// PrivateCatalog allows catalog consumers to retrieve Catalog, Product +// and Version resources under a target resource context. +// +// Catalog is computed based on the Associations linked to the target +// resource and its ancestors. Each association’s +// google.cloud.privatecatalogproducer.v1beta.Catalog is transformed into a +// Catalog. If multiple associations have the same parent +// google.cloud.privatecatalogproducer.v1beta.Catalog, they are +// de-duplicated into one Catalog. Users must have +// cloudprivatecatalog.catalogTargets.get IAM permission on the resource +// context in order to access catalogs. Catalog contains the resource name and +// a subset of data of the original +// google.cloud.privatecatalogproducer.v1beta.Catalog. +// +// Product is child resource of the catalog. A Product contains the resource +// name and a subset of the data of the original +// google.cloud.privatecatalogproducer.v1beta.Product. +// +// Version is child resource of the product. A Version contains the resource +// name and a subset of the data of the original +// google.cloud.privatecatalogproducer.v1beta.Version. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://cloudprivatecatalog.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://cloudprivatecatalog.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://cloudprivatecatalog.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) SearchCatalogs(ctx context.Context, req *privatecatalogpb.SearchCatalogsRequest, opts ...gax.CallOption) *CatalogIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) @@ -379,6 +480,277 @@ func (c *gRPCClient) SearchVersions(ctx context.Context, req *privatecatalogpb.S return it } +// SearchCatalogs search Catalog resources that consumers have access to, within the +// scope of the consumer cloud resource hierarchy context. +func (c *restClient) SearchCatalogs(ctx context.Context, req *privatecatalogpb.SearchCatalogsRequest, opts ...gax.CallOption) *CatalogIterator { + it := &CatalogIterator{} + req = proto.Clone(req).(*privatecatalogpb.SearchCatalogsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*privatecatalogpb.Catalog, string, error) { + resp := &privatecatalogpb.SearchCatalogsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/catalogs:search", req.GetResource()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetQuery() != "" { + params.Add("query", fmt.Sprintf("%v", req.GetQuery())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetCatalogs(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// SearchProducts search Product resources that consumers have access to, within the +// scope of the consumer cloud resource hierarchy context. +func (c *restClient) SearchProducts(ctx context.Context, req *privatecatalogpb.SearchProductsRequest, opts ...gax.CallOption) *ProductIterator { + it := &ProductIterator{} + req = proto.Clone(req).(*privatecatalogpb.SearchProductsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*privatecatalogpb.Product, string, error) { + resp := &privatecatalogpb.SearchProductsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/products:search", req.GetResource()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetQuery() != "" { + params.Add("query", fmt.Sprintf("%v", req.GetQuery())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetProducts(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// SearchVersions search Version resources that consumers have access to, within the +// scope of the consumer cloud resource hierarchy context. +func (c *restClient) SearchVersions(ctx context.Context, req *privatecatalogpb.SearchVersionsRequest, opts ...gax.CallOption) *VersionIterator { + it := &VersionIterator{} + req = proto.Clone(req).(*privatecatalogpb.SearchVersionsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*privatecatalogpb.Version, string, error) { + resp := &privatecatalogpb.SearchVersionsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/versions:search", req.GetResource()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + params.Add("query", fmt.Sprintf("%v", req.GetQuery())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetVersions(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + // CatalogIterator manages a stream of *privatecatalogpb.Catalog. type CatalogIterator struct { items []*privatecatalogpb.Catalog diff --git a/privatecatalog/apiv1beta1/private_catalog_client_example_test.go b/privatecatalog/apiv1beta1/private_catalog_client_example_test.go index 8558ad9e2f70..6e53cde9b0ac 100644 --- a/privatecatalog/apiv1beta1/private_catalog_client_example_test.go +++ b/privatecatalog/apiv1beta1/private_catalog_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := privatecatalog.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_SearchCatalogs() { ctx := context.Background() c, err := privatecatalog.NewClient(ctx) diff --git a/recaptchaenterprise/apiv1beta1/doc.go b/recaptchaenterprise/apiv1beta1/doc.go index 1f90b4097372..ec6a283c3b2e 100644 --- a/recaptchaenterprise/apiv1beta1/doc.go +++ b/recaptchaenterprise/apiv1beta1/doc.go @@ -69,6 +69,8 @@ package recaptchaenterprise // import "cloud.google.com/go/recaptchaenterprise/a import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -157,3 +159,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/recaptchaenterprise/apiv1beta1/gapic_metadata.json b/recaptchaenterprise/apiv1beta1/gapic_metadata.json index feb943220260..7c2a871542e8 100644 --- a/recaptchaenterprise/apiv1beta1/gapic_metadata.json +++ b/recaptchaenterprise/apiv1beta1/gapic_metadata.json @@ -21,6 +21,21 @@ ] } } + }, + "rest": { + "libraryClient": "RecaptchaEnterpriseServiceV1Beta1Client", + "rpcs": { + "AnnotateAssessment": { + "methods": [ + "AnnotateAssessment" + ] + }, + "CreateAssessment": { + "methods": [ + "CreateAssessment" + ] + } + } } } } diff --git a/recaptchaenterprise/apiv1beta1/recaptcha_enterprise_service_v1_beta1_client.go b/recaptchaenterprise/apiv1beta1/recaptcha_enterprise_service_v1_beta1_client.go index b7d626a5d7af..d4f7c913448f 100644 --- a/recaptchaenterprise/apiv1beta1/recaptcha_enterprise_service_v1_beta1_client.go +++ b/recaptchaenterprise/apiv1beta1/recaptcha_enterprise_service_v1_beta1_client.go @@ -17,19 +17,25 @@ package recaptchaenterprise import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" recaptchaenterprisepb "google.golang.org/genproto/googleapis/cloud/recaptchaenterprise/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newRecaptchaEnterpriseServiceV1Beta1ClientHook clientHook @@ -59,6 +65,13 @@ func defaultRecaptchaEnterpriseServiceV1Beta1CallOptions() *RecaptchaEnterpriseS } } +func defaultRecaptchaEnterpriseServiceV1Beta1RESTCallOptions() *RecaptchaEnterpriseServiceV1Beta1CallOptions { + return &RecaptchaEnterpriseServiceV1Beta1CallOptions{ + CreateAssessment: []gax.CallOption{}, + AnnotateAssessment: []gax.CallOption{}, + } +} + // internalRecaptchaEnterpriseServiceV1Beta1Client is an interface that defines the methods available from reCAPTCHA Enterprise API. type internalRecaptchaEnterpriseServiceV1Beta1Client interface { Close() error @@ -193,6 +206,74 @@ func (c *recaptchaEnterpriseServiceV1Beta1GRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type recaptchaEnterpriseServiceV1Beta1RESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing RecaptchaEnterpriseServiceV1Beta1Client + CallOptions **RecaptchaEnterpriseServiceV1Beta1CallOptions +} + +// NewRecaptchaEnterpriseServiceV1Beta1RESTClient creates a new recaptcha enterprise service v1 beta1 rest client. +// +// Service to determine the likelihood an event is legitimate. +func NewRecaptchaEnterpriseServiceV1Beta1RESTClient(ctx context.Context, opts ...option.ClientOption) (*RecaptchaEnterpriseServiceV1Beta1Client, error) { + clientOpts := append(defaultRecaptchaEnterpriseServiceV1Beta1RESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRecaptchaEnterpriseServiceV1Beta1RESTCallOptions() + c := &recaptchaEnterpriseServiceV1Beta1RESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &RecaptchaEnterpriseServiceV1Beta1Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRecaptchaEnterpriseServiceV1Beta1RESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://recaptchaenterprise.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://recaptchaenterprise.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://recaptchaenterprise.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *recaptchaEnterpriseServiceV1Beta1RESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *recaptchaEnterpriseServiceV1Beta1RESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *recaptchaEnterpriseServiceV1Beta1RESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *recaptchaEnterpriseServiceV1Beta1GRPCClient) CreateAssessment(ctx context.Context, req *recaptchaenterprisepb.CreateAssessmentRequest, opts ...gax.CallOption) (*recaptchaenterprisepb.Assessment, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) @@ -236,3 +317,123 @@ func (c *recaptchaEnterpriseServiceV1Beta1GRPCClient) AnnotateAssessment(ctx con } return resp, nil } + +// CreateAssessment creates an Assessment of the likelihood an event is legitimate. +func (c *recaptchaEnterpriseServiceV1Beta1RESTClient) CreateAssessment(ctx context.Context, req *recaptchaenterprisepb.CreateAssessmentRequest, opts ...gax.CallOption) (*recaptchaenterprisepb.Assessment, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetAssessment() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/assessments", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateAssessment[0:len((*c.CallOptions).CreateAssessment):len((*c.CallOptions).CreateAssessment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &recaptchaenterprisepb.Assessment{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// AnnotateAssessment annotates a previously created Assessment to provide additional information +// on whether the event turned out to be authentic or fradulent. +func (c *recaptchaEnterpriseServiceV1Beta1RESTClient) AnnotateAssessment(ctx context.Context, req *recaptchaenterprisepb.AnnotateAssessmentRequest, opts ...gax.CallOption) (*recaptchaenterprisepb.AnnotateAssessmentResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:annotate", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).AnnotateAssessment[0:len((*c.CallOptions).AnnotateAssessment):len((*c.CallOptions).AnnotateAssessment)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &recaptchaenterprisepb.AnnotateAssessmentResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/recaptchaenterprise/apiv1beta1/recaptcha_enterprise_service_v1_beta1_client_example_test.go b/recaptchaenterprise/apiv1beta1/recaptcha_enterprise_service_v1_beta1_client_example_test.go index 98491b05d059..ef75ec7f9c2c 100644 --- a/recaptchaenterprise/apiv1beta1/recaptcha_enterprise_service_v1_beta1_client_example_test.go +++ b/recaptchaenterprise/apiv1beta1/recaptcha_enterprise_service_v1_beta1_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewRecaptchaEnterpriseServiceV1Beta1Client() { _ = c } +func ExampleNewRecaptchaEnterpriseServiceV1Beta1RESTClient() { + ctx := context.Background() + c, err := recaptchaenterprise.NewRecaptchaEnterpriseServiceV1Beta1RESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleRecaptchaEnterpriseServiceV1Beta1Client_CreateAssessment() { ctx := context.Background() c, err := recaptchaenterprise.NewRecaptchaEnterpriseServiceV1Beta1Client(ctx) diff --git a/recommender/apiv1beta1/doc.go b/recommender/apiv1beta1/doc.go index 12fb63a1c09f..76766d151cdf 100644 --- a/recommender/apiv1beta1/doc.go +++ b/recommender/apiv1beta1/doc.go @@ -75,6 +75,8 @@ package recommender // import "cloud.google.com/go/recommender/apiv1beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -163,3 +165,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/recommender/apiv1beta1/gapic_metadata.json b/recommender/apiv1beta1/gapic_metadata.json index cf5bac6c7cf6..badc96dcf0b1 100644 --- a/recommender/apiv1beta1/gapic_metadata.json +++ b/recommender/apiv1beta1/gapic_metadata.json @@ -71,6 +71,71 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "GetInsight": { + "methods": [ + "GetInsight" + ] + }, + "GetInsightTypeConfig": { + "methods": [ + "GetInsightTypeConfig" + ] + }, + "GetRecommendation": { + "methods": [ + "GetRecommendation" + ] + }, + "GetRecommenderConfig": { + "methods": [ + "GetRecommenderConfig" + ] + }, + "ListInsights": { + "methods": [ + "ListInsights" + ] + }, + "ListRecommendations": { + "methods": [ + "ListRecommendations" + ] + }, + "MarkInsightAccepted": { + "methods": [ + "MarkInsightAccepted" + ] + }, + "MarkRecommendationClaimed": { + "methods": [ + "MarkRecommendationClaimed" + ] + }, + "MarkRecommendationFailed": { + "methods": [ + "MarkRecommendationFailed" + ] + }, + "MarkRecommendationSucceeded": { + "methods": [ + "MarkRecommendationSucceeded" + ] + }, + "UpdateInsightTypeConfig": { + "methods": [ + "UpdateInsightTypeConfig" + ] + }, + "UpdateRecommenderConfig": { + "methods": [ + "UpdateRecommenderConfig" + ] + } + } } } } diff --git a/recommender/apiv1beta1/recommender_client.go b/recommender/apiv1beta1/recommender_client.go index 4c127b49ebca..cb27364efef5 100644 --- a/recommender/apiv1beta1/recommender_client.go +++ b/recommender/apiv1beta1/recommender_client.go @@ -17,21 +17,27 @@ package recommender import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" recommenderpb "google.golang.org/genproto/googleapis/cloud/recommender/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -126,6 +132,63 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + ListInsights: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + GetInsight: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + MarkInsightAccepted: []gax.CallOption{}, + ListRecommendations: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + GetRecommendation: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + MarkRecommendationClaimed: []gax.CallOption{}, + MarkRecommendationSucceeded: []gax.CallOption{}, + MarkRecommendationFailed: []gax.CallOption{}, + GetRecommenderConfig: []gax.CallOption{}, + UpdateRecommenderConfig: []gax.CallOption{}, + GetInsightTypeConfig: []gax.CallOption{}, + UpdateInsightTypeConfig: []gax.CallOption{}, + } +} + // internalClient is an interface that defines the methods available from Recommender API. type internalClient interface { Close() error @@ -367,6 +430,77 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new recommender rest client. +// +// Provides insights and recommendations for cloud customers for various +// categories like performance optimization, cost savings, reliability, feature +// discovery, etc. Insights and recommendations are generated automatically +// based on analysis of user resources, configuration and monitoring metrics. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://recommender.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://recommender.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://recommender.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) ListInsights(ctx context.Context, req *recommenderpb.ListInsightsRequest, opts ...gax.CallOption) *InsightIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -657,6 +791,816 @@ func (c *gRPCClient) UpdateInsightTypeConfig(ctx context.Context, req *recommend return resp, nil } +// ListInsights lists insights for the specified Cloud Resource. Requires the +// recommender.*.list IAM permission for the specified insight type. +func (c *restClient) ListInsights(ctx context.Context, req *recommenderpb.ListInsightsRequest, opts ...gax.CallOption) *InsightIterator { + it := &InsightIterator{} + req = proto.Clone(req).(*recommenderpb.ListInsightsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*recommenderpb.Insight, string, error) { + resp := &recommenderpb.ListInsightsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/insights", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetInsights(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetInsight gets the requested insight. Requires the recommender.*.get IAM permission +// for the specified insight type. +func (c *restClient) GetInsight(ctx context.Context, req *recommenderpb.GetInsightRequest, opts ...gax.CallOption) (*recommenderpb.Insight, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetInsight[0:len((*c.CallOptions).GetInsight):len((*c.CallOptions).GetInsight)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &recommenderpb.Insight{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// MarkInsightAccepted marks the Insight State as Accepted. Users can use this method to +// indicate to the Recommender API that they have applied some action based +// on the insight. This stops the insight content from being updated. +// +// MarkInsightAccepted can be applied to insights in ACTIVE state. Requires +// the recommender.*.update IAM permission for the specified insight. +func (c *restClient) MarkInsightAccepted(ctx context.Context, req *recommenderpb.MarkInsightAcceptedRequest, opts ...gax.CallOption) (*recommenderpb.Insight, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:markAccepted", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).MarkInsightAccepted[0:len((*c.CallOptions).MarkInsightAccepted):len((*c.CallOptions).MarkInsightAccepted)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &recommenderpb.Insight{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListRecommendations lists recommendations for the specified Cloud Resource. Requires the +// recommender.*.list IAM permission for the specified recommender. +func (c *restClient) ListRecommendations(ctx context.Context, req *recommenderpb.ListRecommendationsRequest, opts ...gax.CallOption) *RecommendationIterator { + it := &RecommendationIterator{} + req = proto.Clone(req).(*recommenderpb.ListRecommendationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*recommenderpb.Recommendation, string, error) { + resp := &recommenderpb.ListRecommendationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/recommendations", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetRecommendations(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetRecommendation gets the requested recommendation. Requires the recommender.*.get +// IAM permission for the specified recommender. +func (c *restClient) GetRecommendation(ctx context.Context, req *recommenderpb.GetRecommendationRequest, opts ...gax.CallOption) (*recommenderpb.Recommendation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetRecommendation[0:len((*c.CallOptions).GetRecommendation):len((*c.CallOptions).GetRecommendation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &recommenderpb.Recommendation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// MarkRecommendationClaimed marks the Recommendation State as Claimed. Users can use this method to +// indicate to the Recommender API that they are starting to apply the +// recommendation themselves. This stops the recommendation content from being +// updated. Associated insights are frozen and placed in the ACCEPTED state. +// +// MarkRecommendationClaimed can be applied to recommendations in CLAIMED or +// ACTIVE state. +// +// Requires the recommender.*.update IAM permission for the specified +// recommender. +func (c *restClient) MarkRecommendationClaimed(ctx context.Context, req *recommenderpb.MarkRecommendationClaimedRequest, opts ...gax.CallOption) (*recommenderpb.Recommendation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:markClaimed", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).MarkRecommendationClaimed[0:len((*c.CallOptions).MarkRecommendationClaimed):len((*c.CallOptions).MarkRecommendationClaimed)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &recommenderpb.Recommendation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// MarkRecommendationSucceeded marks the Recommendation State as Succeeded. Users can use this method to +// indicate to the Recommender API that they have applied the recommendation +// themselves, and the operation was successful. This stops the recommendation +// content from being updated. Associated insights are frozen and placed in +// the ACCEPTED state. +// +// MarkRecommendationSucceeded can be applied to recommendations in ACTIVE, +// CLAIMED, SUCCEEDED, or FAILED state. +// +// Requires the recommender.*.update IAM permission for the specified +// recommender. +func (c *restClient) MarkRecommendationSucceeded(ctx context.Context, req *recommenderpb.MarkRecommendationSucceededRequest, opts ...gax.CallOption) (*recommenderpb.Recommendation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:markSucceeded", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).MarkRecommendationSucceeded[0:len((*c.CallOptions).MarkRecommendationSucceeded):len((*c.CallOptions).MarkRecommendationSucceeded)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &recommenderpb.Recommendation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// MarkRecommendationFailed marks the Recommendation State as Failed. Users can use this method to +// indicate to the Recommender API that they have applied the recommendation +// themselves, and the operation failed. This stops the recommendation content +// from being updated. Associated insights are frozen and placed in the +// ACCEPTED state. +// +// MarkRecommendationFailed can be applied to recommendations in ACTIVE, +// CLAIMED, SUCCEEDED, or FAILED state. +// +// Requires the recommender.*.update IAM permission for the specified +// recommender. +func (c *restClient) MarkRecommendationFailed(ctx context.Context, req *recommenderpb.MarkRecommendationFailedRequest, opts ...gax.CallOption) (*recommenderpb.Recommendation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:markFailed", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).MarkRecommendationFailed[0:len((*c.CallOptions).MarkRecommendationFailed):len((*c.CallOptions).MarkRecommendationFailed)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &recommenderpb.Recommendation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetRecommenderConfig gets the requested Recommender Config. There is only one instance of the +// config for each Recommender. +func (c *restClient) GetRecommenderConfig(ctx context.Context, req *recommenderpb.GetRecommenderConfigRequest, opts ...gax.CallOption) (*recommenderpb.RecommenderConfig, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetRecommenderConfig[0:len((*c.CallOptions).GetRecommenderConfig):len((*c.CallOptions).GetRecommenderConfig)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &recommenderpb.RecommenderConfig{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateRecommenderConfig updates a Recommender Config. This will create a new revision of the +// config. +func (c *restClient) UpdateRecommenderConfig(ctx context.Context, req *recommenderpb.UpdateRecommenderConfigRequest, opts ...gax.CallOption) (*recommenderpb.RecommenderConfig, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetRecommenderConfig() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetRecommenderConfig().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + if req.GetValidateOnly() { + params.Add("validateOnly", fmt.Sprintf("%v", req.GetValidateOnly())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "recommender_config.name", url.QueryEscape(req.GetRecommenderConfig().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateRecommenderConfig[0:len((*c.CallOptions).UpdateRecommenderConfig):len((*c.CallOptions).UpdateRecommenderConfig)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &recommenderpb.RecommenderConfig{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetInsightTypeConfig gets the requested InsightTypeConfig. There is only one instance of the +// config for each InsightType. +func (c *restClient) GetInsightTypeConfig(ctx context.Context, req *recommenderpb.GetInsightTypeConfigRequest, opts ...gax.CallOption) (*recommenderpb.InsightTypeConfig, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetInsightTypeConfig[0:len((*c.CallOptions).GetInsightTypeConfig):len((*c.CallOptions).GetInsightTypeConfig)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &recommenderpb.InsightTypeConfig{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateInsightTypeConfig updates an InsightTypeConfig change. This will create a new revision of the +// config. +func (c *restClient) UpdateInsightTypeConfig(ctx context.Context, req *recommenderpb.UpdateInsightTypeConfigRequest, opts ...gax.CallOption) (*recommenderpb.InsightTypeConfig, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetInsightTypeConfig() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetInsightTypeConfig().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + if req.GetValidateOnly() { + params.Add("validateOnly", fmt.Sprintf("%v", req.GetValidateOnly())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "insight_type_config.name", url.QueryEscape(req.GetInsightTypeConfig().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateInsightTypeConfig[0:len((*c.CallOptions).UpdateInsightTypeConfig):len((*c.CallOptions).UpdateInsightTypeConfig)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &recommenderpb.InsightTypeConfig{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // InsightIterator manages a stream of *recommenderpb.Insight. type InsightIterator struct { items []*recommenderpb.Insight diff --git a/recommender/apiv1beta1/recommender_client_example_test.go b/recommender/apiv1beta1/recommender_client_example_test.go index 25162a804365..e246b5319b1a 100644 --- a/recommender/apiv1beta1/recommender_client_example_test.go +++ b/recommender/apiv1beta1/recommender_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := recommender.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_ListInsights() { ctx := context.Background() c, err := recommender.NewClient(ctx) diff --git a/redis/apiv1beta1/cloud_redis_client.go b/redis/apiv1beta1/cloud_redis_client.go index 1c61fb352866..7647c1d604ba 100644 --- a/redis/apiv1beta1/cloud_redis_client.go +++ b/redis/apiv1beta1/cloud_redis_client.go @@ -17,9 +17,12 @@ package redis import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" @@ -27,14 +30,17 @@ import ( lroauto "cloud.google.com/go/longrunning/autogen" anypb "github.com/golang/protobuf/ptypes/any" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" redispb "google.golang.org/genproto/googleapis/cloud/redis/v1beta1" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -83,6 +89,22 @@ func defaultCloudRedisCallOptions() *CloudRedisCallOptions { } } +func defaultCloudRedisRESTCallOptions() *CloudRedisCallOptions { + return &CloudRedisCallOptions{ + ListInstances: []gax.CallOption{}, + GetInstance: []gax.CallOption{}, + GetInstanceAuthString: []gax.CallOption{}, + CreateInstance: []gax.CallOption{}, + UpdateInstance: []gax.CallOption{}, + UpgradeInstance: []gax.CallOption{}, + ImportInstance: []gax.CallOption{}, + ExportInstance: []gax.CallOption{}, + FailoverInstance: []gax.CallOption{}, + DeleteInstance: []gax.CallOption{}, + RescheduleMaintenance: []gax.CallOption{}, + } +} + // internalCloudRedisClient is an interface that defines the methods available from Google Cloud Memorystore for Redis API. type internalCloudRedisClient interface { Close() error @@ -426,6 +448,108 @@ func (c *cloudRedisGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type cloudRedisRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing CloudRedisClient + CallOptions **CloudRedisCallOptions +} + +// NewCloudRedisRESTClient creates a new cloud redis rest client. +// +// Configures and manages Cloud Memorystore for Redis instances +// +// Google Cloud Memorystore for Redis v1beta1 +// +// The redis.googleapis.com service implements the Google Cloud Memorystore +// for Redis API and defines the following resource model for managing Redis +// instances: +// +// The service works with a collection of cloud projects, named: /projects/* +// +// Each project has a collection of available locations, named: /locations/* +// +// Each location has a collection of Redis instances, named: /instances/* +// +// As such, Redis instances are resources of the form: +// /projects/{project_id}/locations/{location_id}/instances/{instance_id} +// +// Note that location_id must be referring to a GCP region; for example: +// +// projects/redpepper-1290/locations/us-central1/instances/my-redis +func NewCloudRedisRESTClient(ctx context.Context, opts ...option.ClientOption) (*CloudRedisClient, error) { + clientOpts := append(defaultCloudRedisRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultCloudRedisRESTCallOptions() + c := &cloudRedisRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &CloudRedisClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultCloudRedisRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://redis.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://redis.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://redis.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *cloudRedisRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *cloudRedisRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *cloudRedisRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *cloudRedisGRPCClient) ListInstances(ctx context.Context, req *redispb.ListInstancesRequest, opts ...gax.CallOption) *InstanceIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -702,105 +826,877 @@ func (c *cloudRedisGRPCClient) RescheduleMaintenance(ctx context.Context, req *r }, nil } -// CreateInstanceOperation manages a long-running operation from CreateInstance. -type CreateInstanceOperation struct { - lro *longrunning.Operation -} +// ListInstances lists all Redis instances owned by a project in either the specified +// location (region) or all locations. +// +// The location should have the following format: +// +// projects/{project_id}/locations/{location_id} +// +// If location_id is specified as - (wildcard), then all regions +// available to the project are queried, and the results are aggregated. +func (c *cloudRedisRESTClient) ListInstances(ctx context.Context, req *redispb.ListInstancesRequest, opts ...gax.CallOption) *InstanceIterator { + it := &InstanceIterator{} + req = proto.Clone(req).(*redispb.ListInstancesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*redispb.Instance, string, error) { + resp := &redispb.ListInstancesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/instances", req.GetParent()) -// CreateInstanceOperation returns a new CreateInstanceOperation from a given name. -// The name must be that of a previously created CreateInstanceOperation, possibly from a different process. -func (c *cloudRedisGRPCClient) CreateInstanceOperation(name string) *CreateInstanceOperation { - return &CreateInstanceOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetInstances(), resp.GetNextPageToken(), nil } -} -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. -// -// See documentation of Poll for error-handling information. -func (op *CreateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { - var resp redispb.Instance - if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - return &resp, nil + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it } -// Poll fetches the latest state of the long-running operation. -// -// Poll also fetches the latest metadata, which can be retrieved by Metadata. -// -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and -// the operation has completed with failure, the error is returned and op.Done will return true. -// If Poll succeeds and the operation has completed successfully, -// op.Done will return true, and the response of the operation is returned. -// If Poll succeeds and the operation has not completed, the returned response and error are both nil. -func (op *CreateInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { - var resp redispb.Instance - if err := op.lro.Poll(ctx, &resp, opts...); err != nil { +// GetInstance gets the details of a specific Redis instance. +func (c *cloudRedisRESTClient) GetInstance(ctx context.Context, req *redispb.GetInstanceRequest, opts ...gax.CallOption) (*redispb.Instance, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - if !op.Done() { - return nil, nil + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetInstance[0:len((*c.CallOptions).GetInstance):len((*c.CallOptions).GetInstance)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &redispb.Instance{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e } - return &resp, nil + return resp, nil } -// Metadata returns metadata associated with the long-running operation. -// Metadata itself does not contact the server, but Poll does. -// To get the latest metadata, call this method after a successful call to Poll. -// If the metadata is not available, the returned metadata and error are both nil. -func (op *CreateInstanceOperation) Metadata() (*anypb.Any, error) { - var meta anypb.Any - if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { - return nil, nil - } else if err != nil { +// GetInstanceAuthString gets the AUTH string for a Redis instance. If AUTH is not enabled for the +// instance the response will be empty. This information is not included in +// the details returned to GetInstance. +func (c *cloudRedisRESTClient) GetInstanceAuthString(ctx context.Context, req *redispb.GetInstanceAuthStringRequest, opts ...gax.CallOption) (*redispb.InstanceAuthString, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { return nil, err } - return &meta, nil -} + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/authString", req.GetName()) -// Done reports whether the long-running operation has completed. -func (op *CreateInstanceOperation) Done() bool { - return op.lro.Done() -} + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) -// Name returns the name of the long-running operation. -// The name is assigned by the server and is unique within the service from which the operation is created. -func (op *CreateInstanceOperation) Name() string { - return op.lro.Name() -} + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetInstanceAuthString[0:len((*c.CallOptions).GetInstanceAuthString):len((*c.CallOptions).GetInstanceAuthString)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &redispb.InstanceAuthString{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers -// DeleteInstanceOperation manages a long-running operation from DeleteInstance. -type DeleteInstanceOperation struct { - lro *longrunning.Operation -} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() -// DeleteInstanceOperation returns a new DeleteInstanceOperation from a given name. -// The name must be that of a previously created DeleteInstanceOperation, possibly from a different process. -func (c *cloudRedisGRPCClient) DeleteInstanceOperation(name string) *DeleteInstanceOperation { - return &DeleteInstanceOperation{ - lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e } + return resp, nil } -// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// CreateInstance creates a Redis instance based on the specified tier and memory size. // -// See documentation of Poll for error-handling information. -func (op *DeleteInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { - return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) -} - -// Poll fetches the latest state of the long-running operation. +// By default, the instance is accessible from the project’s +// default network (at https://cloud.google.com/vpc/docs/vpc). // -// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// The creation is executed asynchronously and callers may check the returned +// operation to track its progress. Once the operation is completed the Redis +// instance will be fully functional. The completed longrunning.Operation will +// contain the new instance object in the response field. // -// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// The returned operation is automatically deleted after a few hours, so there +// is no need to call DeleteOperation. +func (c *cloudRedisRESTClient) CreateInstance(ctx context.Context, req *redispb.CreateInstanceRequest, opts ...gax.CallOption) (*CreateInstanceOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetInstance() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/instances", req.GetParent()) + + params := url.Values{} + params.Add("instanceId", fmt.Sprintf("%v", req.GetInstanceId())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &CreateInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UpdateInstance updates the metadata and configuration of a specific Redis instance. +// +// Completed longrunning.Operation will contain the new instance object +// in the response field. The returned operation is automatically deleted +// after a few hours, so there is no need to call DeleteOperation. +func (c *cloudRedisRESTClient) UpdateInstance(ctx context.Context, req *redispb.UpdateInstanceRequest, opts ...gax.CallOption) (*UpdateInstanceOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetInstance() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetInstance().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "instance.name", url.QueryEscape(req.GetInstance().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &UpdateInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UpgradeInstance upgrades Redis instance to the newer Redis version specified in the +// request. +func (c *cloudRedisRESTClient) UpgradeInstance(ctx context.Context, req *redispb.UpgradeInstanceRequest, opts ...gax.CallOption) (*UpgradeInstanceOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:upgrade", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &UpgradeInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ImportInstance import a Redis RDB snapshot file from Cloud Storage into a Redis instance. +// +// Redis may stop serving during this operation. Instance state will be +// IMPORTING for entire operation. When complete, the instance will contain +// only data from the imported file. +// +// The returned operation is automatically deleted after a few hours, so +// there is no need to call DeleteOperation. +func (c *cloudRedisRESTClient) ImportInstance(ctx context.Context, req *redispb.ImportInstanceRequest, opts ...gax.CallOption) (*ImportInstanceOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:import", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &ImportInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// ExportInstance export Redis instance data into a Redis RDB format file in Cloud Storage. +// +// Redis will continue serving during this operation. +// +// The returned operation is automatically deleted after a few hours, so +// there is no need to call DeleteOperation. +func (c *cloudRedisRESTClient) ExportInstance(ctx context.Context, req *redispb.ExportInstanceRequest, opts ...gax.CallOption) (*ExportInstanceOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:export", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &ExportInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// FailoverInstance initiates a failover of the primary node to current replica node for a +// specific STANDARD tier Cloud Memorystore for Redis instance. +func (c *cloudRedisRESTClient) FailoverInstance(ctx context.Context, req *redispb.FailoverInstanceRequest, opts ...gax.CallOption) (*FailoverInstanceOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:failover", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &FailoverInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// DeleteInstance deletes a specific Redis instance. Instance stops serving and data is +// deleted. +func (c *cloudRedisRESTClient) DeleteInstance(ctx context.Context, req *redispb.DeleteInstanceRequest, opts ...gax.CallOption) (*DeleteInstanceOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &DeleteInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// RescheduleMaintenance reschedule maintenance for a given instance in a given project and +// location. +func (c *cloudRedisRESTClient) RescheduleMaintenance(ctx context.Context, req *redispb.RescheduleMaintenanceRequest, opts ...gax.CallOption) (*RescheduleMaintenanceOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:rescheduleMaintenance", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta1/%s", resp.GetName()) + return &RescheduleMaintenanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// CreateInstanceOperation manages a long-running operation from CreateInstance. +type CreateInstanceOperation struct { + lro *longrunning.Operation + pollPath string +} + +// CreateInstanceOperation returns a new CreateInstanceOperation from a given name. +// The name must be that of a previously created CreateInstanceOperation, possibly from a different process. +func (c *cloudRedisGRPCClient) CreateInstanceOperation(name string) *CreateInstanceOperation { + return &CreateInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// CreateInstanceOperation returns a new CreateInstanceOperation from a given name. +// The name must be that of a previously created CreateInstanceOperation, possibly from a different process. +func (c *cloudRedisRESTClient) CreateInstanceOperation(name string) *CreateInstanceOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &CreateInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp redispb.Instance + if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + var resp redispb.Instance + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateInstanceOperation) Metadata() (*anypb.Any, error) { + var meta anypb.Any + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateInstanceOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *CreateInstanceOperation) Name() string { + return op.lro.Name() +} + +// DeleteInstanceOperation manages a long-running operation from DeleteInstance. +type DeleteInstanceOperation struct { + lro *longrunning.Operation + pollPath string +} + +// DeleteInstanceOperation returns a new DeleteInstanceOperation from a given name. +// The name must be that of a previously created DeleteInstanceOperation, possibly from a different process. +func (c *cloudRedisGRPCClient) DeleteInstanceOperation(name string) *DeleteInstanceOperation { + return &DeleteInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// DeleteInstanceOperation returns a new DeleteInstanceOperation from a given name. +// The name must be that of a previously created DeleteInstanceOperation, possibly from a different process. +func (c *cloudRedisRESTClient) DeleteInstanceOperation(name string) *DeleteInstanceOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &DeleteInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *DeleteInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) + return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and // the operation has completed with failure, the error is returned and op.Done will return true. // If Poll succeeds and the operation has completed successfully, // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeleteInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -831,7 +1727,8 @@ func (op *DeleteInstanceOperation) Name() string { // ExportInstanceOperation manages a long-running operation from ExportInstance. type ExportInstanceOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // ExportInstanceOperation returns a new ExportInstanceOperation from a given name. @@ -842,10 +1739,21 @@ func (c *cloudRedisGRPCClient) ExportInstanceOperation(name string) *ExportInsta } } +// ExportInstanceOperation returns a new ExportInstanceOperation from a given name. +// The name must be that of a previously created ExportInstanceOperation, possibly from a different process. +func (c *cloudRedisRESTClient) ExportInstanceOperation(name string) *ExportInstanceOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &ExportInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *ExportInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp redispb.Instance if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -863,6 +1771,7 @@ func (op *ExportInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *ExportInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp redispb.Instance if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -900,7 +1809,8 @@ func (op *ExportInstanceOperation) Name() string { // FailoverInstanceOperation manages a long-running operation from FailoverInstance. type FailoverInstanceOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // FailoverInstanceOperation returns a new FailoverInstanceOperation from a given name. @@ -911,10 +1821,21 @@ func (c *cloudRedisGRPCClient) FailoverInstanceOperation(name string) *FailoverI } } +// FailoverInstanceOperation returns a new FailoverInstanceOperation from a given name. +// The name must be that of a previously created FailoverInstanceOperation, possibly from a different process. +func (c *cloudRedisRESTClient) FailoverInstanceOperation(name string) *FailoverInstanceOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &FailoverInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *FailoverInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp redispb.Instance if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -932,6 +1853,7 @@ func (op *FailoverInstanceOperation) Wait(ctx context.Context, opts ...gax.CallO // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *FailoverInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp redispb.Instance if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -969,7 +1891,8 @@ func (op *FailoverInstanceOperation) Name() string { // ImportInstanceOperation manages a long-running operation from ImportInstance. type ImportInstanceOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // ImportInstanceOperation returns a new ImportInstanceOperation from a given name. @@ -980,10 +1903,21 @@ func (c *cloudRedisGRPCClient) ImportInstanceOperation(name string) *ImportInsta } } +// ImportInstanceOperation returns a new ImportInstanceOperation from a given name. +// The name must be that of a previously created ImportInstanceOperation, possibly from a different process. +func (c *cloudRedisRESTClient) ImportInstanceOperation(name string) *ImportInstanceOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &ImportInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *ImportInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp redispb.Instance if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1001,6 +1935,7 @@ func (op *ImportInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *ImportInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp redispb.Instance if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1038,7 +1973,8 @@ func (op *ImportInstanceOperation) Name() string { // RescheduleMaintenanceOperation manages a long-running operation from RescheduleMaintenance. type RescheduleMaintenanceOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // RescheduleMaintenanceOperation returns a new RescheduleMaintenanceOperation from a given name. @@ -1049,10 +1985,21 @@ func (c *cloudRedisGRPCClient) RescheduleMaintenanceOperation(name string) *Resc } } +// RescheduleMaintenanceOperation returns a new RescheduleMaintenanceOperation from a given name. +// The name must be that of a previously created RescheduleMaintenanceOperation, possibly from a different process. +func (c *cloudRedisRESTClient) RescheduleMaintenanceOperation(name string) *RescheduleMaintenanceOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &RescheduleMaintenanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *RescheduleMaintenanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp redispb.Instance if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1070,6 +2017,7 @@ func (op *RescheduleMaintenanceOperation) Wait(ctx context.Context, opts ...gax. // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *RescheduleMaintenanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp redispb.Instance if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1107,7 +2055,8 @@ func (op *RescheduleMaintenanceOperation) Name() string { // UpdateInstanceOperation manages a long-running operation from UpdateInstance. type UpdateInstanceOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UpdateInstanceOperation returns a new UpdateInstanceOperation from a given name. @@ -1118,10 +2067,21 @@ func (c *cloudRedisGRPCClient) UpdateInstanceOperation(name string) *UpdateInsta } } +// UpdateInstanceOperation returns a new UpdateInstanceOperation from a given name. +// The name must be that of a previously created UpdateInstanceOperation, possibly from a different process. +func (c *cloudRedisRESTClient) UpdateInstanceOperation(name string) *UpdateInstanceOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &UpdateInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UpdateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp redispb.Instance if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1139,6 +2099,7 @@ func (op *UpdateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UpdateInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp redispb.Instance if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -1176,7 +2137,8 @@ func (op *UpdateInstanceOperation) Name() string { // UpgradeInstanceOperation manages a long-running operation from UpgradeInstance. type UpgradeInstanceOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UpgradeInstanceOperation returns a new UpgradeInstanceOperation from a given name. @@ -1187,10 +2149,21 @@ func (c *cloudRedisGRPCClient) UpgradeInstanceOperation(name string) *UpgradeIns } } +// UpgradeInstanceOperation returns a new UpgradeInstanceOperation from a given name. +// The name must be that of a previously created UpgradeInstanceOperation, possibly from a different process. +func (c *cloudRedisRESTClient) UpgradeInstanceOperation(name string) *UpgradeInstanceOperation { + override := fmt.Sprintf("/v1beta1/%s", name) + return &UpgradeInstanceOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UpgradeInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp redispb.Instance if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -1208,6 +2181,7 @@ func (op *UpgradeInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOp // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UpgradeInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp redispb.Instance if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/redis/apiv1beta1/cloud_redis_client_example_test.go b/redis/apiv1beta1/cloud_redis_client_example_test.go index b1f878212c9c..ab50d4098907 100644 --- a/redis/apiv1beta1/cloud_redis_client_example_test.go +++ b/redis/apiv1beta1/cloud_redis_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewCloudRedisClient() { _ = c } +func ExampleNewCloudRedisRESTClient() { + ctx := context.Background() + c, err := redis.NewCloudRedisRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleCloudRedisClient_ListInstances() { ctx := context.Background() c, err := redis.NewCloudRedisClient(ctx) diff --git a/redis/apiv1beta1/doc.go b/redis/apiv1beta1/doc.go index 24764250ff53..ce6a825946a5 100644 --- a/redis/apiv1beta1/doc.go +++ b/redis/apiv1beta1/doc.go @@ -77,6 +77,8 @@ package redis // import "cloud.google.com/go/redis/apiv1beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -165,3 +167,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/redis/apiv1beta1/gapic_metadata.json b/redis/apiv1beta1/gapic_metadata.json index 664f42b80447..1dcb7d0777b1 100644 --- a/redis/apiv1beta1/gapic_metadata.json +++ b/redis/apiv1beta1/gapic_metadata.json @@ -66,6 +66,66 @@ ] } } + }, + "rest": { + "libraryClient": "CloudRedisClient", + "rpcs": { + "CreateInstance": { + "methods": [ + "CreateInstance" + ] + }, + "DeleteInstance": { + "methods": [ + "DeleteInstance" + ] + }, + "ExportInstance": { + "methods": [ + "ExportInstance" + ] + }, + "FailoverInstance": { + "methods": [ + "FailoverInstance" + ] + }, + "GetInstance": { + "methods": [ + "GetInstance" + ] + }, + "GetInstanceAuthString": { + "methods": [ + "GetInstanceAuthString" + ] + }, + "ImportInstance": { + "methods": [ + "ImportInstance" + ] + }, + "ListInstances": { + "methods": [ + "ListInstances" + ] + }, + "RescheduleMaintenance": { + "methods": [ + "RescheduleMaintenance" + ] + }, + "UpdateInstance": { + "methods": [ + "UpdateInstance" + ] + }, + "UpgradeInstance": { + "methods": [ + "UpgradeInstance" + ] + } + } } } } diff --git a/scheduler/apiv1beta1/cloud_scheduler_client.go b/scheduler/apiv1beta1/cloud_scheduler_client.go index a75b082185ae..00cedbf584ac 100644 --- a/scheduler/apiv1beta1/cloud_scheduler_client.go +++ b/scheduler/apiv1beta1/cloud_scheduler_client.go @@ -17,21 +17,27 @@ package scheduler import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" schedulerpb "google.golang.org/genproto/googleapis/cloud/scheduler/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -129,6 +135,69 @@ func defaultCloudSchedulerCallOptions() *CloudSchedulerCallOptions { } } +func defaultCloudSchedulerRESTCallOptions() *CloudSchedulerCallOptions { + return &CloudSchedulerCallOptions{ + ListJobs: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + GetJob: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + CreateJob: []gax.CallOption{}, + UpdateJob: []gax.CallOption{}, + DeleteJob: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + PauseJob: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + ResumeJob: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + RunJob: []gax.CallOption{}, + } +} + // internalCloudSchedulerClient is an interface that defines the methods available from Cloud Scheduler API. type internalCloudSchedulerClient interface { Close() error @@ -322,6 +391,75 @@ func (c *cloudSchedulerGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type cloudSchedulerRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing CloudSchedulerClient + CallOptions **CloudSchedulerCallOptions +} + +// NewCloudSchedulerRESTClient creates a new cloud scheduler rest client. +// +// The Cloud Scheduler API allows external entities to reliably +// schedule asynchronous jobs. +func NewCloudSchedulerRESTClient(ctx context.Context, opts ...option.ClientOption) (*CloudSchedulerClient, error) { + clientOpts := append(defaultCloudSchedulerRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultCloudSchedulerRESTCallOptions() + c := &cloudSchedulerRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &CloudSchedulerClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultCloudSchedulerRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://cloudscheduler.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://cloudscheduler.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://cloudscheduler.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *cloudSchedulerRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *cloudSchedulerRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *cloudSchedulerRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *cloudSchedulerGRPCClient) ListJobs(ctx context.Context, req *schedulerpb.ListJobsRequest, opts ...gax.CallOption) *JobIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -517,6 +655,507 @@ func (c *cloudSchedulerGRPCClient) RunJob(ctx context.Context, req *schedulerpb. return resp, nil } +// ListJobs lists jobs. +func (c *cloudSchedulerRESTClient) ListJobs(ctx context.Context, req *schedulerpb.ListJobsRequest, opts ...gax.CallOption) *JobIterator { + it := &JobIterator{} + req = proto.Clone(req).(*schedulerpb.ListJobsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*schedulerpb.Job, string, error) { + resp := &schedulerpb.ListJobsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/jobs", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetJobs(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetJob gets a job. +func (c *cloudSchedulerRESTClient) GetJob(ctx context.Context, req *schedulerpb.GetJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetJob[0:len((*c.CallOptions).GetJob):len((*c.CallOptions).GetJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &schedulerpb.Job{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateJob creates a job. +func (c *cloudSchedulerRESTClient) CreateJob(ctx context.Context, req *schedulerpb.CreateJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetJob() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/jobs", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateJob[0:len((*c.CallOptions).CreateJob):len((*c.CallOptions).CreateJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &schedulerpb.Job{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateJob updates a job. +// +// If successful, the updated Job is returned. If the job does +// not exist, NOT_FOUND is returned. +// +// If UpdateJob does not successfully return, it is possible for the +// job to be in an Job.State.UPDATE_FAILED state. A job in this state may +// not be executed. If this happens, retry the UpdateJob request +// until a successful response is received. +func (c *cloudSchedulerRESTClient) UpdateJob(ctx context.Context, req *schedulerpb.UpdateJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetJob() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetJob().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "job.name", url.QueryEscape(req.GetJob().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateJob[0:len((*c.CallOptions).UpdateJob):len((*c.CallOptions).UpdateJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &schedulerpb.Job{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteJob deletes a job. +func (c *cloudSchedulerRESTClient) DeleteJob(ctx context.Context, req *schedulerpb.DeleteJobRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// PauseJob pauses a job. +// +// If a job is paused then the system will stop executing the job +// until it is re-enabled via ResumeJob. The +// state of the job is stored in state; if paused it +// will be set to Job.State.PAUSED. A job must be in Job.State.ENABLED +// to be paused. +func (c *cloudSchedulerRESTClient) PauseJob(ctx context.Context, req *schedulerpb.PauseJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:pause", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).PauseJob[0:len((*c.CallOptions).PauseJob):len((*c.CallOptions).PauseJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &schedulerpb.Job{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ResumeJob resume a job. +// +// This method reenables a job after it has been Job.State.PAUSED. The +// state of a job is stored in Job.state; after calling this method it +// will be set to Job.State.ENABLED. A job must be in +// Job.State.PAUSED to be resumed. +func (c *cloudSchedulerRESTClient) ResumeJob(ctx context.Context, req *schedulerpb.ResumeJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:resume", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ResumeJob[0:len((*c.CallOptions).ResumeJob):len((*c.CallOptions).ResumeJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &schedulerpb.Job{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// RunJob forces a job to run now. +// +// When this method is called, Cloud Scheduler will dispatch the job, even +// if the job is already running. +func (c *cloudSchedulerRESTClient) RunJob(ctx context.Context, req *schedulerpb.RunJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:run", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).RunJob[0:len((*c.CallOptions).RunJob):len((*c.CallOptions).RunJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &schedulerpb.Job{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // JobIterator manages a stream of *schedulerpb.Job. type JobIterator struct { items []*schedulerpb.Job diff --git a/scheduler/apiv1beta1/cloud_scheduler_client_example_test.go b/scheduler/apiv1beta1/cloud_scheduler_client_example_test.go index 00503e4d5bec..f067e705ca4d 100644 --- a/scheduler/apiv1beta1/cloud_scheduler_client_example_test.go +++ b/scheduler/apiv1beta1/cloud_scheduler_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewCloudSchedulerClient() { _ = c } +func ExampleNewCloudSchedulerRESTClient() { + ctx := context.Background() + c, err := scheduler.NewCloudSchedulerRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleCloudSchedulerClient_ListJobs() { ctx := context.Background() c, err := scheduler.NewCloudSchedulerClient(ctx) diff --git a/scheduler/apiv1beta1/doc.go b/scheduler/apiv1beta1/doc.go index 3afababdcd1f..b93c4c0a9f46 100644 --- a/scheduler/apiv1beta1/doc.go +++ b/scheduler/apiv1beta1/doc.go @@ -77,6 +77,8 @@ package scheduler // import "cloud.google.com/go/scheduler/apiv1beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -165,3 +167,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/scheduler/apiv1beta1/gapic_metadata.json b/scheduler/apiv1beta1/gapic_metadata.json index 0af02b964f97..1c16dec29b62 100644 --- a/scheduler/apiv1beta1/gapic_metadata.json +++ b/scheduler/apiv1beta1/gapic_metadata.json @@ -51,6 +51,51 @@ ] } } + }, + "rest": { + "libraryClient": "CloudSchedulerClient", + "rpcs": { + "CreateJob": { + "methods": [ + "CreateJob" + ] + }, + "DeleteJob": { + "methods": [ + "DeleteJob" + ] + }, + "GetJob": { + "methods": [ + "GetJob" + ] + }, + "ListJobs": { + "methods": [ + "ListJobs" + ] + }, + "PauseJob": { + "methods": [ + "PauseJob" + ] + }, + "ResumeJob": { + "methods": [ + "ResumeJob" + ] + }, + "RunJob": { + "methods": [ + "RunJob" + ] + }, + "UpdateJob": { + "methods": [ + "UpdateJob" + ] + } + } } } } diff --git a/secretmanager/apiv1beta1/doc.go b/secretmanager/apiv1beta1/doc.go index bb8f64461b37..1253c9f428e5 100644 --- a/secretmanager/apiv1beta1/doc.go +++ b/secretmanager/apiv1beta1/doc.go @@ -78,6 +78,8 @@ package secretmanager // import "cloud.google.com/go/secretmanager/apiv1beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -166,3 +168,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/secretmanager/apiv1beta1/gapic_metadata.json b/secretmanager/apiv1beta1/gapic_metadata.json index 31f38b730d9a..af202c980567 100644 --- a/secretmanager/apiv1beta1/gapic_metadata.json +++ b/secretmanager/apiv1beta1/gapic_metadata.json @@ -86,6 +86,86 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "AccessSecretVersion": { + "methods": [ + "AccessSecretVersion" + ] + }, + "AddSecretVersion": { + "methods": [ + "AddSecretVersion" + ] + }, + "CreateSecret": { + "methods": [ + "CreateSecret" + ] + }, + "DeleteSecret": { + "methods": [ + "DeleteSecret" + ] + }, + "DestroySecretVersion": { + "methods": [ + "DestroySecretVersion" + ] + }, + "DisableSecretVersion": { + "methods": [ + "DisableSecretVersion" + ] + }, + "EnableSecretVersion": { + "methods": [ + "EnableSecretVersion" + ] + }, + "GetIamPolicy": { + "methods": [ + "GetIamPolicy" + ] + }, + "GetSecret": { + "methods": [ + "GetSecret" + ] + }, + "GetSecretVersion": { + "methods": [ + "GetSecretVersion" + ] + }, + "ListSecretVersions": { + "methods": [ + "ListSecretVersions" + ] + }, + "ListSecrets": { + "methods": [ + "ListSecrets" + ] + }, + "SetIamPolicy": { + "methods": [ + "SetIamPolicy" + ] + }, + "TestIamPermissions": { + "methods": [ + "TestIamPermissions" + ] + }, + "UpdateSecret": { + "methods": [ + "UpdateSecret" + ] + } + } } } } diff --git a/secretmanager/apiv1beta1/secret_manager_client.go b/secretmanager/apiv1beta1/secret_manager_client.go index e99cef1b8ed3..4417b562c004 100644 --- a/secretmanager/apiv1beta1/secret_manager_client.go +++ b/secretmanager/apiv1beta1/secret_manager_client.go @@ -17,22 +17,28 @@ package secretmanager import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1beta1" iampb "google.golang.org/genproto/googleapis/iam/v1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -100,6 +106,36 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + ListSecrets: []gax.CallOption{}, + CreateSecret: []gax.CallOption{}, + AddSecretVersion: []gax.CallOption{}, + GetSecret: []gax.CallOption{}, + UpdateSecret: []gax.CallOption{}, + DeleteSecret: []gax.CallOption{}, + ListSecretVersions: []gax.CallOption{}, + GetSecretVersion: []gax.CallOption{}, + AccessSecretVersion: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DisableSecretVersion: []gax.CallOption{}, + EnableSecretVersion: []gax.CallOption{}, + DestroySecretVersion: []gax.CallOption{}, + SetIamPolicy: []gax.CallOption{}, + GetIamPolicy: []gax.CallOption{}, + TestIamPermissions: []gax.CallOption{}, + } +} + // internalClient is an interface that defines the methods available from Secret Manager API. type internalClient interface { Close() error @@ -354,6 +390,81 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new secret manager service rest client. +// +// Secret Manager Service +// +// Manages secrets and operations using those secrets. Implements a REST +// model with the following objects: +// +// Secret +// +// SecretVersion +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://secretmanager.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://secretmanager.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://secretmanager.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) ListSecrets(ctx context.Context, req *secretmanagerpb.ListSecretsRequest, opts ...gax.CallOption) *SecretIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -726,6 +837,949 @@ func (c *gRPCClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamP return resp, nil } +// ListSecrets lists Secrets. +func (c *restClient) ListSecrets(ctx context.Context, req *secretmanagerpb.ListSecretsRequest, opts ...gax.CallOption) *SecretIterator { + it := &SecretIterator{} + req = proto.Clone(req).(*secretmanagerpb.ListSecretsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*secretmanagerpb.Secret, string, error) { + resp := &secretmanagerpb.ListSecretsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/secrets", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetSecrets(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CreateSecret creates a new Secret containing no SecretVersions. +func (c *restClient) CreateSecret(ctx context.Context, req *secretmanagerpb.CreateSecretRequest, opts ...gax.CallOption) (*secretmanagerpb.Secret, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetSecret() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/secrets", req.GetParent()) + + params := url.Values{} + params.Add("secretId", fmt.Sprintf("%v", req.GetSecretId())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateSecret[0:len((*c.CallOptions).CreateSecret):len((*c.CallOptions).CreateSecret)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &secretmanagerpb.Secret{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// AddSecretVersion creates a new SecretVersion containing secret data and attaches +// it to an existing Secret. +func (c *restClient) AddSecretVersion(ctx context.Context, req *secretmanagerpb.AddSecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.SecretVersion, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:addVersion", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).AddSecretVersion[0:len((*c.CallOptions).AddSecretVersion):len((*c.CallOptions).AddSecretVersion)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &secretmanagerpb.SecretVersion{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetSecret gets metadata for a given Secret. +func (c *restClient) GetSecret(ctx context.Context, req *secretmanagerpb.GetSecretRequest, opts ...gax.CallOption) (*secretmanagerpb.Secret, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetSecret[0:len((*c.CallOptions).GetSecret):len((*c.CallOptions).GetSecret)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &secretmanagerpb.Secret{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateSecret updates metadata of an existing Secret. +func (c *restClient) UpdateSecret(ctx context.Context, req *secretmanagerpb.UpdateSecretRequest, opts ...gax.CallOption) (*secretmanagerpb.Secret, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetSecret() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetSecret().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "secret.name", url.QueryEscape(req.GetSecret().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateSecret[0:len((*c.CallOptions).UpdateSecret):len((*c.CallOptions).UpdateSecret)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &secretmanagerpb.Secret{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteSecret deletes a Secret. +func (c *restClient) DeleteSecret(ctx context.Context, req *secretmanagerpb.DeleteSecretRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// ListSecretVersions lists SecretVersions. This call does not return secret +// data. +func (c *restClient) ListSecretVersions(ctx context.Context, req *secretmanagerpb.ListSecretVersionsRequest, opts ...gax.CallOption) *SecretVersionIterator { + it := &SecretVersionIterator{} + req = proto.Clone(req).(*secretmanagerpb.ListSecretVersionsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*secretmanagerpb.SecretVersion, string, error) { + resp := &secretmanagerpb.ListSecretVersionsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/versions", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetVersions(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetSecretVersion gets metadata for a SecretVersion. +// +// projects/*/secrets/*/versions/latest is an alias to the latest +// SecretVersion. +func (c *restClient) GetSecretVersion(ctx context.Context, req *secretmanagerpb.GetSecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.SecretVersion, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetSecretVersion[0:len((*c.CallOptions).GetSecretVersion):len((*c.CallOptions).GetSecretVersion)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &secretmanagerpb.SecretVersion{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// AccessSecretVersion accesses a SecretVersion. This call returns the secret data. +// +// projects/*/secrets/*/versions/latest is an alias to the latest +// SecretVersion. +func (c *restClient) AccessSecretVersion(ctx context.Context, req *secretmanagerpb.AccessSecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.AccessSecretVersionResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:access", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).AccessSecretVersion[0:len((*c.CallOptions).AccessSecretVersion):len((*c.CallOptions).AccessSecretVersion)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &secretmanagerpb.AccessSecretVersionResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DisableSecretVersion disables a SecretVersion. +// +// Sets the state of the SecretVersion to +// DISABLED. +func (c *restClient) DisableSecretVersion(ctx context.Context, req *secretmanagerpb.DisableSecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.SecretVersion, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:disable", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).DisableSecretVersion[0:len((*c.CallOptions).DisableSecretVersion):len((*c.CallOptions).DisableSecretVersion)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &secretmanagerpb.SecretVersion{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// EnableSecretVersion enables a SecretVersion. +// +// Sets the state of the SecretVersion to +// ENABLED. +func (c *restClient) EnableSecretVersion(ctx context.Context, req *secretmanagerpb.EnableSecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.SecretVersion, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:enable", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).EnableSecretVersion[0:len((*c.CallOptions).EnableSecretVersion):len((*c.CallOptions).EnableSecretVersion)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &secretmanagerpb.SecretVersion{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DestroySecretVersion destroys a SecretVersion. +// +// Sets the state of the SecretVersion to +// DESTROYED and irrevocably destroys the +// secret data. +func (c *restClient) DestroySecretVersion(ctx context.Context, req *secretmanagerpb.DestroySecretVersionRequest, opts ...gax.CallOption) (*secretmanagerpb.SecretVersion, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:destroy", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).DestroySecretVersion[0:len((*c.CallOptions).DestroySecretVersion):len((*c.CallOptions).DestroySecretVersion)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &secretmanagerpb.SecretVersion{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// SetIamPolicy sets the access control policy on the specified secret. Replaces any +// existing policy. +// +// Permissions on SecretVersions are enforced according +// to the policy set on the associated Secret. +func (c *restClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:setIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SetIamPolicy[0:len((*c.CallOptions).SetIamPolicy):len((*c.CallOptions).SetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetIamPolicy gets the access control policy for a secret. +// Returns empty policy if the secret exists and does not have a policy set. +func (c *restClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:getIamPolicy", req.GetResource()) + + params := url.Values{} + if req.GetOptions().GetRequestedPolicyVersion() != 0 { + params.Add("options.requestedPolicyVersion", fmt.Sprintf("%v", req.GetOptions().GetRequestedPolicyVersion())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetIamPolicy[0:len((*c.CallOptions).GetIamPolicy):len((*c.CallOptions).GetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// TestIamPermissions returns permissions that a caller has for the specified secret. +// If the secret does not exist, this call returns an empty set of +// permissions, not a NOT_FOUND error. +// +// Note: This operation is designed to be used for building permission-aware +// UIs and command-line tools, not for authorization checking. This operation +// may “fail open” without warning. +func (c *restClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:testIamPermissions", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).TestIamPermissions[0:len((*c.CallOptions).TestIamPermissions):len((*c.CallOptions).TestIamPermissions)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.TestIamPermissionsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // SecretIterator manages a stream of *secretmanagerpb.Secret. type SecretIterator struct { items []*secretmanagerpb.Secret diff --git a/secretmanager/apiv1beta1/secret_manager_client_example_test.go b/secretmanager/apiv1beta1/secret_manager_client_example_test.go index b5aaf953180a..d9855dfc5805 100644 --- a/secretmanager/apiv1beta1/secret_manager_client_example_test.go +++ b/secretmanager/apiv1beta1/secret_manager_client_example_test.go @@ -37,6 +37,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := secretmanager.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_ListSecrets() { ctx := context.Background() c, err := secretmanager.NewClient(ctx) diff --git a/servicedirectory/apiv1beta1/doc.go b/servicedirectory/apiv1beta1/doc.go index b222f5550dc0..20d306bc297d 100644 --- a/servicedirectory/apiv1beta1/doc.go +++ b/servicedirectory/apiv1beta1/doc.go @@ -72,6 +72,8 @@ package servicedirectory // import "cloud.google.com/go/servicedirectory/apiv1be import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -160,3 +162,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/servicedirectory/apiv1beta1/gapic_metadata.json b/servicedirectory/apiv1beta1/gapic_metadata.json index 13f4d2fec391..2571dd8cbf54 100644 --- a/servicedirectory/apiv1beta1/gapic_metadata.json +++ b/servicedirectory/apiv1beta1/gapic_metadata.json @@ -16,6 +16,16 @@ ] } } + }, + "rest": { + "libraryClient": "LookupClient", + "rpcs": { + "ResolveService": { + "methods": [ + "ResolveService" + ] + } + } } } }, @@ -115,6 +125,101 @@ ] } } + }, + "rest": { + "libraryClient": "RegistrationClient", + "rpcs": { + "CreateEndpoint": { + "methods": [ + "CreateEndpoint" + ] + }, + "CreateNamespace": { + "methods": [ + "CreateNamespace" + ] + }, + "CreateService": { + "methods": [ + "CreateService" + ] + }, + "DeleteEndpoint": { + "methods": [ + "DeleteEndpoint" + ] + }, + "DeleteNamespace": { + "methods": [ + "DeleteNamespace" + ] + }, + "DeleteService": { + "methods": [ + "DeleteService" + ] + }, + "GetEndpoint": { + "methods": [ + "GetEndpoint" + ] + }, + "GetIamPolicy": { + "methods": [ + "GetIamPolicy" + ] + }, + "GetNamespace": { + "methods": [ + "GetNamespace" + ] + }, + "GetService": { + "methods": [ + "GetService" + ] + }, + "ListEndpoints": { + "methods": [ + "ListEndpoints" + ] + }, + "ListNamespaces": { + "methods": [ + "ListNamespaces" + ] + }, + "ListServices": { + "methods": [ + "ListServices" + ] + }, + "SetIamPolicy": { + "methods": [ + "SetIamPolicy" + ] + }, + "TestIamPermissions": { + "methods": [ + "TestIamPermissions" + ] + }, + "UpdateEndpoint": { + "methods": [ + "UpdateEndpoint" + ] + }, + "UpdateNamespace": { + "methods": [ + "UpdateNamespace" + ] + }, + "UpdateService": { + "methods": [ + "UpdateService" + ] + } + } } } } diff --git a/servicedirectory/apiv1beta1/lookup_client.go b/servicedirectory/apiv1beta1/lookup_client.go index 00ff275d9103..4e8c19187c3d 100644 --- a/servicedirectory/apiv1beta1/lookup_client.go +++ b/servicedirectory/apiv1beta1/lookup_client.go @@ -17,20 +17,26 @@ package servicedirectory import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" servicedirectorypb "google.golang.org/genproto/googleapis/cloud/servicedirectory/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newLookupClientHook clientHook @@ -69,6 +75,22 @@ func defaultLookupCallOptions() *LookupCallOptions { } } +func defaultLookupRESTCallOptions() *LookupCallOptions { + return &LookupCallOptions{ + ResolveService: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + } +} + // internalLookupClient is an interface that defines the methods available from Service Directory API. type internalLookupClient interface { Close() error @@ -198,6 +220,74 @@ func (c *lookupGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type lookupRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing LookupClient + CallOptions **LookupCallOptions +} + +// NewLookupRESTClient creates a new lookup service rest client. +// +// Service Directory API for looking up service data at runtime. +func NewLookupRESTClient(ctx context.Context, opts ...option.ClientOption) (*LookupClient, error) { + clientOpts := append(defaultLookupRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultLookupRESTCallOptions() + c := &lookupRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &LookupClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultLookupRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://servicedirectory.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://servicedirectory.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://servicedirectory.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *lookupRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *lookupRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *lookupRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *lookupGRPCClient) ResolveService(ctx context.Context, req *servicedirectorypb.ResolveServiceRequest, opts ...gax.CallOption) (*servicedirectorypb.ResolveServiceResponse, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 15000*time.Millisecond) @@ -219,3 +309,64 @@ func (c *lookupGRPCClient) ResolveService(ctx context.Context, req *servicedirec } return resp, nil } + +// ResolveService returns a service and its +// associated endpoints. +// Resolving a service is not considered an active developer method. +func (c *lookupRESTClient) ResolveService(ctx context.Context, req *servicedirectorypb.ResolveServiceRequest, opts ...gax.CallOption) (*servicedirectorypb.ResolveServiceResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:resolve", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ResolveService[0:len((*c.CallOptions).ResolveService):len((*c.CallOptions).ResolveService)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &servicedirectorypb.ResolveServiceResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/servicedirectory/apiv1beta1/lookup_client_example_test.go b/servicedirectory/apiv1beta1/lookup_client_example_test.go index 9c6236092ee1..bb73c2d93d1d 100644 --- a/servicedirectory/apiv1beta1/lookup_client_example_test.go +++ b/servicedirectory/apiv1beta1/lookup_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewLookupClient() { _ = c } +func ExampleNewLookupRESTClient() { + ctx := context.Background() + c, err := servicedirectory.NewLookupRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleLookupClient_ResolveService() { ctx := context.Background() c, err := servicedirectory.NewLookupClient(ctx) diff --git a/servicedirectory/apiv1beta1/registration_client.go b/servicedirectory/apiv1beta1/registration_client.go index 4d9bdabddec2..113161b1cb0f 100644 --- a/servicedirectory/apiv1beta1/registration_client.go +++ b/servicedirectory/apiv1beta1/registration_client.go @@ -17,22 +17,28 @@ package servicedirectory import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" servicedirectorypb "google.golang.org/genproto/googleapis/cloud/servicedirectory/v1beta1" iampb "google.golang.org/genproto/googleapis/iam/v1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -293,6 +299,209 @@ func defaultRegistrationCallOptions() *RegistrationCallOptions { } } +func defaultRegistrationRESTCallOptions() *RegistrationCallOptions { + return &RegistrationCallOptions{ + CreateNamespace: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListNamespaces: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetNamespace: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateNamespace: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DeleteNamespace: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CreateService: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListServices: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetService: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateService: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DeleteService: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + CreateEndpoint: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + ListEndpoints: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetEndpoint: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + UpdateEndpoint: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + DeleteEndpoint: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + GetIamPolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + SetIamPolicy: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + TestIamPermissions: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusInternalServerError) + }), + }, + } +} + // internalRegistrationClient is an interface that defines the methods available from Service Directory API. type internalRegistrationClient interface { Close() error @@ -552,6 +761,88 @@ func (c *registrationGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type registrationRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing RegistrationClient + CallOptions **RegistrationCallOptions +} + +// NewRegistrationRESTClient creates a new registration service rest client. +// +// Service Directory API for registering services. It defines the following +// resource model: +// +// The API has a collection of +// Namespace +// resources, named projects/*/locations/*/namespaces/*. +// +// Each Namespace has a collection of +// Service resources, named +// projects/*/locations/*/namespaces/*/services/*. +// +// Each Service has a collection of +// Endpoint +// resources, named +// projects/*/locations/*/namespaces/*/services/*/endpoints/*. +func NewRegistrationRESTClient(ctx context.Context, opts ...option.ClientOption) (*RegistrationClient, error) { + clientOpts := append(defaultRegistrationRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRegistrationRESTCallOptions() + c := ®istrationRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &RegistrationClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRegistrationRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://servicedirectory.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://servicedirectory.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://servicedirectory.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *registrationRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *registrationRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *registrationRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *registrationGRPCClient) CreateNamespace(ctx context.Context, req *servicedirectorypb.CreateNamespaceRequest, opts ...gax.CallOption) (*servicedirectorypb.Namespace, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 15000*time.Millisecond) @@ -1005,6 +1296,1124 @@ func (c *registrationGRPCClient) TestIamPermissions(ctx context.Context, req *ia return resp, nil } +// CreateNamespace creates a namespace, and returns the new namespace. +func (c *registrationRESTClient) CreateNamespace(ctx context.Context, req *servicedirectorypb.CreateNamespaceRequest, opts ...gax.CallOption) (*servicedirectorypb.Namespace, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetNamespace() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/namespaces", req.GetParent()) + + params := url.Values{} + params.Add("namespaceId", fmt.Sprintf("%v", req.GetNamespaceId())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateNamespace[0:len((*c.CallOptions).CreateNamespace):len((*c.CallOptions).CreateNamespace)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &servicedirectorypb.Namespace{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListNamespaces lists all namespaces. +func (c *registrationRESTClient) ListNamespaces(ctx context.Context, req *servicedirectorypb.ListNamespacesRequest, opts ...gax.CallOption) *NamespaceIterator { + it := &NamespaceIterator{} + req = proto.Clone(req).(*servicedirectorypb.ListNamespacesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*servicedirectorypb.Namespace, string, error) { + resp := &servicedirectorypb.ListNamespacesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/namespaces", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetOrderBy() != "" { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetNamespaces(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetNamespace gets a namespace. +func (c *registrationRESTClient) GetNamespace(ctx context.Context, req *servicedirectorypb.GetNamespaceRequest, opts ...gax.CallOption) (*servicedirectorypb.Namespace, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetNamespace[0:len((*c.CallOptions).GetNamespace):len((*c.CallOptions).GetNamespace)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &servicedirectorypb.Namespace{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateNamespace updates a namespace. +func (c *registrationRESTClient) UpdateNamespace(ctx context.Context, req *servicedirectorypb.UpdateNamespaceRequest, opts ...gax.CallOption) (*servicedirectorypb.Namespace, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetNamespace() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetNamespace().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "namespace.name", url.QueryEscape(req.GetNamespace().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateNamespace[0:len((*c.CallOptions).UpdateNamespace):len((*c.CallOptions).UpdateNamespace)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &servicedirectorypb.Namespace{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteNamespace deletes a namespace. This also deletes all services and endpoints in +// the namespace. +func (c *registrationRESTClient) DeleteNamespace(ctx context.Context, req *servicedirectorypb.DeleteNamespaceRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// CreateService creates a service, and returns the new service. +func (c *registrationRESTClient) CreateService(ctx context.Context, req *servicedirectorypb.CreateServiceRequest, opts ...gax.CallOption) (*servicedirectorypb.Service, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetService() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/services", req.GetParent()) + + params := url.Values{} + params.Add("serviceId", fmt.Sprintf("%v", req.GetServiceId())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateService[0:len((*c.CallOptions).CreateService):len((*c.CallOptions).CreateService)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &servicedirectorypb.Service{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListServices lists all services belonging to a namespace. +func (c *registrationRESTClient) ListServices(ctx context.Context, req *servicedirectorypb.ListServicesRequest, opts ...gax.CallOption) *ServiceIterator { + it := &ServiceIterator{} + req = proto.Clone(req).(*servicedirectorypb.ListServicesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*servicedirectorypb.Service, string, error) { + resp := &servicedirectorypb.ListServicesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/services", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetOrderBy() != "" { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetServices(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetService gets a service. +func (c *registrationRESTClient) GetService(ctx context.Context, req *servicedirectorypb.GetServiceRequest, opts ...gax.CallOption) (*servicedirectorypb.Service, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetService[0:len((*c.CallOptions).GetService):len((*c.CallOptions).GetService)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &servicedirectorypb.Service{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateService updates a service. +func (c *registrationRESTClient) UpdateService(ctx context.Context, req *servicedirectorypb.UpdateServiceRequest, opts ...gax.CallOption) (*servicedirectorypb.Service, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetService() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetService().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "service.name", url.QueryEscape(req.GetService().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateService[0:len((*c.CallOptions).UpdateService):len((*c.CallOptions).UpdateService)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &servicedirectorypb.Service{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteService deletes a service. This also deletes all endpoints associated with +// the service. +func (c *registrationRESTClient) DeleteService(ctx context.Context, req *servicedirectorypb.DeleteServiceRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// CreateEndpoint creates an endpoint, and returns the new endpoint. +func (c *registrationRESTClient) CreateEndpoint(ctx context.Context, req *servicedirectorypb.CreateEndpointRequest, opts ...gax.CallOption) (*servicedirectorypb.Endpoint, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetEndpoint() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/endpoints", req.GetParent()) + + params := url.Values{} + params.Add("endpointId", fmt.Sprintf("%v", req.GetEndpointId())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateEndpoint[0:len((*c.CallOptions).CreateEndpoint):len((*c.CallOptions).CreateEndpoint)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &servicedirectorypb.Endpoint{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListEndpoints lists all endpoints. +func (c *registrationRESTClient) ListEndpoints(ctx context.Context, req *servicedirectorypb.ListEndpointsRequest, opts ...gax.CallOption) *EndpointIterator { + it := &EndpointIterator{} + req = proto.Clone(req).(*servicedirectorypb.ListEndpointsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*servicedirectorypb.Endpoint, string, error) { + resp := &servicedirectorypb.ListEndpointsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v/endpoints", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetOrderBy() != "" { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetEndpoints(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetEndpoint gets an endpoint. +func (c *registrationRESTClient) GetEndpoint(ctx context.Context, req *servicedirectorypb.GetEndpointRequest, opts ...gax.CallOption) (*servicedirectorypb.Endpoint, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetEndpoint[0:len((*c.CallOptions).GetEndpoint):len((*c.CallOptions).GetEndpoint)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &servicedirectorypb.Endpoint{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateEndpoint updates an endpoint. +func (c *registrationRESTClient) UpdateEndpoint(ctx context.Context, req *servicedirectorypb.UpdateEndpointRequest, opts ...gax.CallOption) (*servicedirectorypb.Endpoint, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetEndpoint() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetEndpoint().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "endpoint.name", url.QueryEscape(req.GetEndpoint().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateEndpoint[0:len((*c.CallOptions).UpdateEndpoint):len((*c.CallOptions).UpdateEndpoint)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &servicedirectorypb.Endpoint{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteEndpoint deletes an endpoint. +func (c *registrationRESTClient) DeleteEndpoint(ctx context.Context, req *servicedirectorypb.DeleteEndpointRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// GetIamPolicy gets the IAM Policy for a resource (namespace or service only). +func (c *registrationRESTClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:getIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetIamPolicy[0:len((*c.CallOptions).GetIamPolicy):len((*c.CallOptions).GetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// SetIamPolicy sets the IAM Policy for a resource (namespace or service only). +func (c *registrationRESTClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:setIamPolicy", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SetIamPolicy[0:len((*c.CallOptions).SetIamPolicy):len((*c.CallOptions).SetIamPolicy)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.Policy{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// TestIamPermissions tests IAM permissions for a resource (namespace or service only). +func (c *registrationRESTClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/%v:testIamPermissions", req.GetResource()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).TestIamPermissions[0:len((*c.CallOptions).TestIamPermissions):len((*c.CallOptions).TestIamPermissions)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &iampb.TestIamPermissionsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // EndpointIterator manages a stream of *servicedirectorypb.Endpoint. type EndpointIterator struct { items []*servicedirectorypb.Endpoint diff --git a/servicedirectory/apiv1beta1/registration_client_example_test.go b/servicedirectory/apiv1beta1/registration_client_example_test.go index 42741e5b25f6..1301a9269305 100644 --- a/servicedirectory/apiv1beta1/registration_client_example_test.go +++ b/servicedirectory/apiv1beta1/registration_client_example_test.go @@ -37,6 +37,18 @@ func ExampleNewRegistrationClient() { _ = c } +func ExampleNewRegistrationRESTClient() { + ctx := context.Background() + c, err := servicedirectory.NewRegistrationRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleRegistrationClient_CreateNamespace() { ctx := context.Background() c, err := servicedirectory.NewRegistrationClient(ctx) diff --git a/speech/apiv1p1beta1/adaptation_client.go b/speech/apiv1p1beta1/adaptation_client.go index 9a258a505228..5d74fc6bb8ab 100644 --- a/speech/apiv1p1beta1/adaptation_client.go +++ b/speech/apiv1p1beta1/adaptation_client.go @@ -17,19 +17,25 @@ package speech import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" speechpb "google.golang.org/genproto/googleapis/cloud/speech/v1p1beta1" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -76,6 +82,21 @@ func defaultAdaptationCallOptions() *AdaptationCallOptions { } } +func defaultAdaptationRESTCallOptions() *AdaptationCallOptions { + return &AdaptationCallOptions{ + CreatePhraseSet: []gax.CallOption{}, + GetPhraseSet: []gax.CallOption{}, + ListPhraseSet: []gax.CallOption{}, + UpdatePhraseSet: []gax.CallOption{}, + DeletePhraseSet: []gax.CallOption{}, + CreateCustomClass: []gax.CallOption{}, + GetCustomClass: []gax.CallOption{}, + ListCustomClasses: []gax.CallOption{}, + UpdateCustomClass: []gax.CallOption{}, + DeleteCustomClass: []gax.CallOption{}, + } +} + // internalAdaptationClient is an interface that defines the methods available from Cloud Speech-to-Text API. type internalAdaptationClient interface { Close() error @@ -259,6 +280,74 @@ func (c *adaptationGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type adaptationRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing AdaptationClient + CallOptions **AdaptationCallOptions +} + +// NewAdaptationRESTClient creates a new adaptation rest client. +// +// Service that implements Google Cloud Speech Adaptation API. +func NewAdaptationRESTClient(ctx context.Context, opts ...option.ClientOption) (*AdaptationClient, error) { + clientOpts := append(defaultAdaptationRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultAdaptationRESTCallOptions() + c := &adaptationRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &AdaptationClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultAdaptationRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://speech.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://speech.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://speech.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *adaptationRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *adaptationRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *adaptationRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *adaptationGRPCClient) CreatePhraseSet(ctx context.Context, req *speechpb.CreatePhraseSetRequest, opts ...gax.CallOption) (*speechpb.PhraseSet, error) { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -477,6 +566,610 @@ func (c *adaptationGRPCClient) DeleteCustomClass(ctx context.Context, req *speec return err } +// CreatePhraseSet create a set of phrase hints. Each item in the set can be a single word or +// a multi-word phrase. The items in the PhraseSet are favored by the +// recognition model when you send a call that includes the PhraseSet. +func (c *adaptationRESTClient) CreatePhraseSet(ctx context.Context, req *speechpb.CreatePhraseSetRequest, opts ...gax.CallOption) (*speechpb.PhraseSet, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1p1beta1/%v/phraseSets", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreatePhraseSet[0:len((*c.CallOptions).CreatePhraseSet):len((*c.CallOptions).CreatePhraseSet)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &speechpb.PhraseSet{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetPhraseSet get a phrase set. +func (c *adaptationRESTClient) GetPhraseSet(ctx context.Context, req *speechpb.GetPhraseSetRequest, opts ...gax.CallOption) (*speechpb.PhraseSet, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1p1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetPhraseSet[0:len((*c.CallOptions).GetPhraseSet):len((*c.CallOptions).GetPhraseSet)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &speechpb.PhraseSet{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListPhraseSet list phrase sets. +func (c *adaptationRESTClient) ListPhraseSet(ctx context.Context, req *speechpb.ListPhraseSetRequest, opts ...gax.CallOption) *PhraseSetIterator { + it := &PhraseSetIterator{} + req = proto.Clone(req).(*speechpb.ListPhraseSetRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*speechpb.PhraseSet, string, error) { + resp := &speechpb.ListPhraseSetResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1p1beta1/%v/phraseSets", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetPhraseSets(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// UpdatePhraseSet update a phrase set. +func (c *adaptationRESTClient) UpdatePhraseSet(ctx context.Context, req *speechpb.UpdatePhraseSetRequest, opts ...gax.CallOption) (*speechpb.PhraseSet, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetPhraseSet() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1p1beta1/%v", req.GetPhraseSet().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "phrase_set.name", url.QueryEscape(req.GetPhraseSet().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdatePhraseSet[0:len((*c.CallOptions).UpdatePhraseSet):len((*c.CallOptions).UpdatePhraseSet)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &speechpb.PhraseSet{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeletePhraseSet delete a phrase set. +func (c *adaptationRESTClient) DeletePhraseSet(ctx context.Context, req *speechpb.DeletePhraseSetRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1p1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// CreateCustomClass create a custom class. +func (c *adaptationRESTClient) CreateCustomClass(ctx context.Context, req *speechpb.CreateCustomClassRequest, opts ...gax.CallOption) (*speechpb.CustomClass, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1p1beta1/%v/customClasses", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateCustomClass[0:len((*c.CallOptions).CreateCustomClass):len((*c.CallOptions).CreateCustomClass)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &speechpb.CustomClass{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetCustomClass get a custom class. +func (c *adaptationRESTClient) GetCustomClass(ctx context.Context, req *speechpb.GetCustomClassRequest, opts ...gax.CallOption) (*speechpb.CustomClass, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1p1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetCustomClass[0:len((*c.CallOptions).GetCustomClass):len((*c.CallOptions).GetCustomClass)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &speechpb.CustomClass{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// ListCustomClasses list custom classes. +func (c *adaptationRESTClient) ListCustomClasses(ctx context.Context, req *speechpb.ListCustomClassesRequest, opts ...gax.CallOption) *CustomClassIterator { + it := &CustomClassIterator{} + req = proto.Clone(req).(*speechpb.ListCustomClassesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*speechpb.CustomClass, string, error) { + resp := &speechpb.ListCustomClassesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1p1beta1/%v/customClasses", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetCustomClasses(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// UpdateCustomClass update a custom class. +func (c *adaptationRESTClient) UpdateCustomClass(ctx context.Context, req *speechpb.UpdateCustomClassRequest, opts ...gax.CallOption) (*speechpb.CustomClass, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetCustomClass() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1p1beta1/%v", req.GetCustomClass().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "custom_class.name", url.QueryEscape(req.GetCustomClass().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateCustomClass[0:len((*c.CallOptions).UpdateCustomClass):len((*c.CallOptions).UpdateCustomClass)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &speechpb.CustomClass{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteCustomClass delete a custom class. +func (c *adaptationRESTClient) DeleteCustomClass(ctx context.Context, req *speechpb.DeleteCustomClassRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v1p1beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + // CustomClassIterator manages a stream of *speechpb.CustomClass. type CustomClassIterator struct { items []*speechpb.CustomClass diff --git a/speech/apiv1p1beta1/adaptation_client_example_test.go b/speech/apiv1p1beta1/adaptation_client_example_test.go index 0b1eb2ca40a0..548aecf24cc0 100644 --- a/speech/apiv1p1beta1/adaptation_client_example_test.go +++ b/speech/apiv1p1beta1/adaptation_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewAdaptationClient() { _ = c } +func ExampleNewAdaptationRESTClient() { + ctx := context.Background() + c, err := speech.NewAdaptationRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleAdaptationClient_CreatePhraseSet() { ctx := context.Background() c, err := speech.NewAdaptationClient(ctx) diff --git a/speech/apiv1p1beta1/doc.go b/speech/apiv1p1beta1/doc.go index 84f8a27eae10..aa175095b9f8 100644 --- a/speech/apiv1p1beta1/doc.go +++ b/speech/apiv1p1beta1/doc.go @@ -71,6 +71,8 @@ package speech // import "cloud.google.com/go/speech/apiv1p1beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -159,3 +161,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/speech/apiv1p1beta1/gapic_metadata.json b/speech/apiv1p1beta1/gapic_metadata.json index 37520a28aee8..1d26bcc56829 100644 --- a/speech/apiv1p1beta1/gapic_metadata.json +++ b/speech/apiv1p1beta1/gapic_metadata.json @@ -61,6 +61,61 @@ ] } } + }, + "rest": { + "libraryClient": "AdaptationClient", + "rpcs": { + "CreateCustomClass": { + "methods": [ + "CreateCustomClass" + ] + }, + "CreatePhraseSet": { + "methods": [ + "CreatePhraseSet" + ] + }, + "DeleteCustomClass": { + "methods": [ + "DeleteCustomClass" + ] + }, + "DeletePhraseSet": { + "methods": [ + "DeletePhraseSet" + ] + }, + "GetCustomClass": { + "methods": [ + "GetCustomClass" + ] + }, + "GetPhraseSet": { + "methods": [ + "GetPhraseSet" + ] + }, + "ListCustomClasses": { + "methods": [ + "ListCustomClasses" + ] + }, + "ListPhraseSet": { + "methods": [ + "ListPhraseSet" + ] + }, + "UpdateCustomClass": { + "methods": [ + "UpdateCustomClass" + ] + }, + "UpdatePhraseSet": { + "methods": [ + "UpdatePhraseSet" + ] + } + } } } }, @@ -85,6 +140,26 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "LongRunningRecognize": { + "methods": [ + "LongRunningRecognize" + ] + }, + "Recognize": { + "methods": [ + "Recognize" + ] + }, + "StreamingRecognize": { + "methods": [ + "StreamingRecognize" + ] + } + } } } } diff --git a/speech/apiv1p1beta1/speech_client.go b/speech/apiv1p1beta1/speech_client.go index a8ed5fff9677..6780db034ffe 100644 --- a/speech/apiv1p1beta1/speech_client.go +++ b/speech/apiv1p1beta1/speech_client.go @@ -17,21 +17,29 @@ package speech import ( + "bytes" "context" + "fmt" + "io/ioutil" "math" + "net/http" + "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" speechpb "google.golang.org/genproto/googleapis/cloud/speech/v1p1beta1" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newClientHook clientHook @@ -85,6 +93,34 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + Recognize: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + LongRunningRecognize: []gax.CallOption{}, + StreamingRecognize: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + } +} + // internalClient is an interface that defines the methods available from Cloud Speech-to-Text API. type internalClient interface { Close() error @@ -259,6 +295,89 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new speech rest client. +// +// Service that implements Google Cloud Speech API. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://speech.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://speech.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://speech.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) Recognize(ctx context.Context, req *speechpb.RecognizeRequest, opts ...gax.CallOption) (*speechpb.RecognizeResponse, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 5000000*time.Millisecond) @@ -316,9 +435,140 @@ func (c *gRPCClient) StreamingRecognize(ctx context.Context, opts ...gax.CallOpt return resp, nil } +// Recognize performs synchronous speech recognition: receive results after all audio +// has been sent and processed. +func (c *restClient) Recognize(ctx context.Context, req *speechpb.RecognizeRequest, opts ...gax.CallOption) (*speechpb.RecognizeResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1p1beta1/speech:recognize") + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).Recognize[0:len((*c.CallOptions).Recognize):len((*c.CallOptions).Recognize)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &speechpb.RecognizeResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// LongRunningRecognize performs asynchronous speech recognition: receive results via the +// google.longrunning.Operations interface. Returns either an +// Operation.error or an Operation.response which contains +// a LongRunningRecognizeResponse message. +// For more information on asynchronous speech recognition, see the +// how-to (at https://cloud.google.com/speech-to-text/docs/async-recognize). +func (c *restClient) LongRunningRecognize(ctx context.Context, req *speechpb.LongRunningRecognizeRequest, opts ...gax.CallOption) (*LongRunningRecognizeOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1p1beta1/speech:longrunningrecognize") + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1p1beta1/operations/%s", resp.GetName()) + return &LongRunningRecognizeOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// StreamingRecognize performs bidirectional streaming speech recognition: receive results while +// sending audio. This method is only available via the gRPC API (not REST). +func (c *restClient) StreamingRecognize(ctx context.Context, opts ...gax.CallOption) (speechpb.Speech_StreamingRecognizeClient, error) { + return nil, fmt.Errorf("StreamingRecognize not yet supported for REST clients") +} + // LongRunningRecognizeOperation manages a long-running operation from LongRunningRecognize. type LongRunningRecognizeOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // LongRunningRecognizeOperation returns a new LongRunningRecognizeOperation from a given name. @@ -329,10 +579,21 @@ func (c *gRPCClient) LongRunningRecognizeOperation(name string) *LongRunningReco } } +// LongRunningRecognizeOperation returns a new LongRunningRecognizeOperation from a given name. +// The name must be that of a previously created LongRunningRecognizeOperation, possibly from a different process. +func (c *restClient) LongRunningRecognizeOperation(name string) *LongRunningRecognizeOperation { + override := fmt.Sprintf("/v1p1beta1/operations/%s", name) + return &LongRunningRecognizeOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *LongRunningRecognizeOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*speechpb.LongRunningRecognizeResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp speechpb.LongRunningRecognizeResponse if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -350,6 +611,7 @@ func (op *LongRunningRecognizeOperation) Wait(ctx context.Context, opts ...gax.C // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *LongRunningRecognizeOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*speechpb.LongRunningRecognizeResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp speechpb.LongRunningRecognizeResponse if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/speech/apiv1p1beta1/speech_client_example_test.go b/speech/apiv1p1beta1/speech_client_example_test.go index 4018aa7ef5e5..a10fd143f6dc 100644 --- a/speech/apiv1p1beta1/speech_client_example_test.go +++ b/speech/apiv1p1beta1/speech_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := speech.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_Recognize() { ctx := context.Background() c, err := speech.NewClient(ctx) diff --git a/talent/apiv4beta1/company_client.go b/talent/apiv4beta1/company_client.go index 17cea046800c..520248ac0b91 100644 --- a/talent/apiv4beta1/company_client.go +++ b/talent/apiv4beta1/company_client.go @@ -17,22 +17,28 @@ package talent import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" talentpb "google.golang.org/genproto/googleapis/cloud/talent/v4beta1" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -104,6 +110,47 @@ func defaultCompanyCallOptions() *CompanyCallOptions { } } +func defaultCompanyRESTCallOptions() *CompanyCallOptions { + return &CompanyCallOptions{ + CreateCompany: []gax.CallOption{}, + GetCompany: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + UpdateCompany: []gax.CallOption{}, + DeleteCompany: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + ListCompanies: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + GetOperation: []gax.CallOption{}, + } +} + // internalCompanyClient is an interface that defines the methods available from Cloud Talent Solution API. type internalCompanyClient interface { Close() error @@ -265,6 +312,74 @@ func (c *companyGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type companyRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing CompanyClient + CallOptions **CompanyCallOptions +} + +// NewCompanyRESTClient creates a new company service rest client. +// +// A service that handles company management, including CRUD and enumeration. +func NewCompanyRESTClient(ctx context.Context, opts ...option.ClientOption) (*CompanyClient, error) { + clientOpts := append(defaultCompanyRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultCompanyRESTCallOptions() + c := &companyRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &CompanyClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultCompanyRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://jobs.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://jobs.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://jobs.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *companyRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *companyRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *companyRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *companyGRPCClient) CreateCompany(ctx context.Context, req *talentpb.CreateCompanyRequest, opts ...gax.CallOption) (*talentpb.Company, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond) @@ -411,6 +526,356 @@ func (c *companyGRPCClient) GetOperation(ctx context.Context, req *longrunningpb return resp, nil } +// CreateCompany creates a new company entity. +func (c *companyRESTClient) CreateCompany(ctx context.Context, req *talentpb.CreateCompanyRequest, opts ...gax.CallOption) (*talentpb.Company, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v/companies", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateCompany[0:len((*c.CallOptions).CreateCompany):len((*c.CallOptions).CreateCompany)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &talentpb.Company{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetCompany retrieves specified company. +func (c *companyRESTClient) GetCompany(ctx context.Context, req *talentpb.GetCompanyRequest, opts ...gax.CallOption) (*talentpb.Company, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetCompany[0:len((*c.CallOptions).GetCompany):len((*c.CallOptions).GetCompany)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &talentpb.Company{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateCompany updates specified company. +func (c *companyRESTClient) UpdateCompany(ctx context.Context, req *talentpb.UpdateCompanyRequest, opts ...gax.CallOption) (*talentpb.Company, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetCompany().GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "company.name", url.QueryEscape(req.GetCompany().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateCompany[0:len((*c.CallOptions).UpdateCompany):len((*c.CallOptions).UpdateCompany)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &talentpb.Company{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteCompany deletes specified company. +// Prerequisite: The company has no jobs associated with it. +func (c *companyRESTClient) DeleteCompany(ctx context.Context, req *talentpb.DeleteCompanyRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// ListCompanies lists all companies associated with the project. +func (c *companyRESTClient) ListCompanies(ctx context.Context, req *talentpb.ListCompaniesRequest, opts ...gax.CallOption) *CompanyIterator { + it := &CompanyIterator{} + req = proto.Clone(req).(*talentpb.ListCompaniesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*talentpb.Company, string, error) { + resp := &talentpb.ListCompaniesResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v/companies", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetRequireOpenJobs() { + params.Add("requireOpenJobs", fmt.Sprintf("%v", req.GetRequireOpenJobs())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetCompanies(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *companyRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // CompanyIterator manages a stream of *talentpb.Company. type CompanyIterator struct { items []*talentpb.Company diff --git a/talent/apiv4beta1/company_client_example_test.go b/talent/apiv4beta1/company_client_example_test.go index 5ef40d7de369..c85e33bb5a8a 100644 --- a/talent/apiv4beta1/company_client_example_test.go +++ b/talent/apiv4beta1/company_client_example_test.go @@ -37,6 +37,18 @@ func ExampleNewCompanyClient() { _ = c } +func ExampleNewCompanyRESTClient() { + ctx := context.Background() + c, err := talent.NewCompanyRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleCompanyClient_CreateCompany() { ctx := context.Background() c, err := talent.NewCompanyClient(ctx) diff --git a/talent/apiv4beta1/completion_client.go b/talent/apiv4beta1/completion_client.go index 91be773c0417..5963bbc60e9e 100644 --- a/talent/apiv4beta1/completion_client.go +++ b/talent/apiv4beta1/completion_client.go @@ -19,19 +19,24 @@ package talent import ( "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" talentpb "google.golang.org/genproto/googleapis/cloud/talent/v4beta1" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newCompletionClientHook clientHook @@ -72,6 +77,23 @@ func defaultCompletionCallOptions() *CompletionCallOptions { } } +func defaultCompletionRESTCallOptions() *CompletionCallOptions { + return &CompletionCallOptions{ + CompleteQuery: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + GetOperation: []gax.CallOption{}, + } +} + // internalCompletionClient is an interface that defines the methods available from Cloud Talent Solution API. type internalCompletionClient interface { Close() error @@ -209,6 +231,74 @@ func (c *completionGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type completionRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing CompletionClient + CallOptions **CompletionCallOptions +} + +// NewCompletionRESTClient creates a new completion rest client. +// +// A service handles auto completion. +func NewCompletionRESTClient(ctx context.Context, opts ...option.ClientOption) (*CompletionClient, error) { + clientOpts := append(defaultCompletionRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultCompletionRESTCallOptions() + c := &completionRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &CompletionClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultCompletionRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://jobs.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://jobs.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://jobs.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *completionRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *completionRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *completionRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *completionGRPCClient) CompleteQuery(ctx context.Context, req *talentpb.CompleteQueryRequest, opts ...gax.CallOption) (*talentpb.CompleteQueryResponse, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond) @@ -247,3 +337,128 @@ func (c *completionGRPCClient) GetOperation(ctx context.Context, req *longrunnin } return resp, nil } + +// CompleteQuery completes the specified prefix with keyword suggestions. +// Intended for use by a job search auto-complete search box. +func (c *completionRESTClient) CompleteQuery(ctx context.Context, req *talentpb.CompleteQueryRequest, opts ...gax.CallOption) (*talentpb.CompleteQueryResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v:complete", req.GetParent()) + + params := url.Values{} + if req.GetCompany() != "" { + params.Add("company", fmt.Sprintf("%v", req.GetCompany())) + } + if req.GetLanguageCodes() != nil { + params.Add("languageCodes", fmt.Sprintf("%v", req.GetLanguageCodes())) + } + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + params.Add("query", fmt.Sprintf("%v", req.GetQuery())) + if req.GetScope() != 0 { + params.Add("scope", fmt.Sprintf("%v", req.GetScope())) + } + if req.GetType() != 0 { + params.Add("type", fmt.Sprintf("%v", req.GetType())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CompleteQuery[0:len((*c.CallOptions).CompleteQuery):len((*c.CallOptions).CompleteQuery)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &talentpb.CompleteQueryResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *completionRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/talent/apiv4beta1/completion_client_example_test.go b/talent/apiv4beta1/completion_client_example_test.go index d43ddb445197..32498217afd8 100644 --- a/talent/apiv4beta1/completion_client_example_test.go +++ b/talent/apiv4beta1/completion_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewCompletionClient() { _ = c } +func ExampleNewCompletionRESTClient() { + ctx := context.Background() + c, err := talent.NewCompletionRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleCompletionClient_CompleteQuery() { ctx := context.Background() c, err := talent.NewCompletionClient(ctx) diff --git a/talent/apiv4beta1/doc.go b/talent/apiv4beta1/doc.go index a1293a125af0..4974d7bdd00b 100644 --- a/talent/apiv4beta1/doc.go +++ b/talent/apiv4beta1/doc.go @@ -72,6 +72,8 @@ package talent // import "cloud.google.com/go/talent/apiv4beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -161,3 +163,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/talent/apiv4beta1/event_client.go b/talent/apiv4beta1/event_client.go index db71b6026817..6014ee5cd3e2 100644 --- a/talent/apiv4beta1/event_client.go +++ b/talent/apiv4beta1/event_client.go @@ -17,20 +17,26 @@ package talent import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" talentpb "google.golang.org/genproto/googleapis/cloud/talent/v4beta1" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newEventClientHook clientHook @@ -60,6 +66,13 @@ func defaultEventCallOptions() *EventCallOptions { } } +func defaultEventRESTCallOptions() *EventCallOptions { + return &EventCallOptions{ + CreateClientEvent: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + } +} + // internalEventClient is an interface that defines the methods available from Cloud Talent Solution API. type internalEventClient interface { Close() error @@ -202,6 +215,74 @@ func (c *eventGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type eventRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing EventClient + CallOptions **EventCallOptions +} + +// NewEventRESTClient creates a new event service rest client. +// +// A service handles client event report. +func NewEventRESTClient(ctx context.Context, opts ...option.ClientOption) (*EventClient, error) { + clientOpts := append(defaultEventRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultEventRESTCallOptions() + c := &eventRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &EventClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultEventRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://jobs.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://jobs.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://jobs.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *eventRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *eventRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *eventRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *eventGRPCClient) CreateClientEvent(ctx context.Context, req *talentpb.CreateClientEventRequest, opts ...gax.CallOption) (*talentpb.ClientEvent, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond) @@ -240,3 +321,121 @@ func (c *eventGRPCClient) GetOperation(ctx context.Context, req *longrunningpb.G } return resp, nil } + +// CreateClientEvent report events issued when end user interacts with customer’s application +// that uses Cloud Talent Solution. You may inspect the created events in +// self service +// tools (at https://console.cloud.google.com/talent-solution/overview). +// Learn +// more (at https://cloud.google.com/talent-solution/docs/management-tools) +// about self service tools. +func (c *eventRESTClient) CreateClientEvent(ctx context.Context, req *talentpb.CreateClientEventRequest, opts ...gax.CallOption) (*talentpb.ClientEvent, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v/clientEvents", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateClientEvent[0:len((*c.CallOptions).CreateClientEvent):len((*c.CallOptions).CreateClientEvent)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &talentpb.ClientEvent{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *eventRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/talent/apiv4beta1/event_client_example_test.go b/talent/apiv4beta1/event_client_example_test.go index 83c62a235f8b..9b9b7715814e 100644 --- a/talent/apiv4beta1/event_client_example_test.go +++ b/talent/apiv4beta1/event_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewEventClient() { _ = c } +func ExampleNewEventRESTClient() { + ctx := context.Background() + c, err := talent.NewEventRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleEventClient_CreateClientEvent() { ctx := context.Background() c, err := talent.NewEventClient(ctx) diff --git a/talent/apiv4beta1/gapic_metadata.json b/talent/apiv4beta1/gapic_metadata.json index 1ecf7b917ccd..30501198da84 100644 --- a/talent/apiv4beta1/gapic_metadata.json +++ b/talent/apiv4beta1/gapic_metadata.json @@ -41,6 +41,41 @@ ] } } + }, + "rest": { + "libraryClient": "CompanyClient", + "rpcs": { + "CreateCompany": { + "methods": [ + "CreateCompany" + ] + }, + "DeleteCompany": { + "methods": [ + "DeleteCompany" + ] + }, + "GetCompany": { + "methods": [ + "GetCompany" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListCompanies": { + "methods": [ + "ListCompanies" + ] + }, + "UpdateCompany": { + "methods": [ + "UpdateCompany" + ] + } + } } } }, @@ -60,6 +95,21 @@ ] } } + }, + "rest": { + "libraryClient": "CompletionClient", + "rpcs": { + "CompleteQuery": { + "methods": [ + "CompleteQuery" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + } + } } } }, @@ -79,6 +129,21 @@ ] } } + }, + "rest": { + "libraryClient": "EventClient", + "rpcs": { + "CreateClientEvent": { + "methods": [ + "CreateClientEvent" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + } + } } } }, @@ -143,6 +208,66 @@ ] } } + }, + "rest": { + "libraryClient": "JobClient", + "rpcs": { + "BatchCreateJobs": { + "methods": [ + "BatchCreateJobs" + ] + }, + "BatchDeleteJobs": { + "methods": [ + "BatchDeleteJobs" + ] + }, + "BatchUpdateJobs": { + "methods": [ + "BatchUpdateJobs" + ] + }, + "CreateJob": { + "methods": [ + "CreateJob" + ] + }, + "DeleteJob": { + "methods": [ + "DeleteJob" + ] + }, + "GetJob": { + "methods": [ + "GetJob" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "ListJobs": { + "methods": [ + "ListJobs" + ] + }, + "SearchJobs": { + "methods": [ + "SearchJobs" + ] + }, + "SearchJobsForAlert": { + "methods": [ + "SearchJobsForAlert" + ] + }, + "UpdateJob": { + "methods": [ + "UpdateJob" + ] + } + } } } }, @@ -182,6 +307,41 @@ ] } } + }, + "rest": { + "libraryClient": "TenantClient", + "rpcs": { + "CreateTenant": { + "methods": [ + "CreateTenant" + ] + }, + "DeleteTenant": { + "methods": [ + "DeleteTenant" + ] + }, + "GetOperation": { + "methods": [ + "GetOperation" + ] + }, + "GetTenant": { + "methods": [ + "GetTenant" + ] + }, + "ListTenants": { + "methods": [ + "ListTenants" + ] + }, + "UpdateTenant": { + "methods": [ + "UpdateTenant" + ] + } + } } } } diff --git a/talent/apiv4beta1/job_client.go b/talent/apiv4beta1/job_client.go index 71080b9764e6..28f11045bd89 100644 --- a/talent/apiv4beta1/job_client.go +++ b/talent/apiv4beta1/job_client.go @@ -17,24 +17,30 @@ package talent import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" talentpb "google.golang.org/genproto/googleapis/cloud/talent/v4beta1" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -116,6 +122,52 @@ func defaultJobCallOptions() *JobCallOptions { } } +func defaultJobRESTCallOptions() *JobCallOptions { + return &JobCallOptions{ + CreateJob: []gax.CallOption{}, + BatchCreateJobs: []gax.CallOption{}, + GetJob: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + UpdateJob: []gax.CallOption{}, + BatchUpdateJobs: []gax.CallOption{}, + DeleteJob: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + BatchDeleteJobs: []gax.CallOption{}, + ListJobs: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + SearchJobs: []gax.CallOption{}, + SearchJobsForAlert: []gax.CallOption{}, + GetOperation: []gax.CallOption{}, + } +} + // internalJobClient is an interface that defines the methods available from Cloud Talent Solution API. type internalJobClient interface { Close() error @@ -364,6 +416,89 @@ func (c *jobGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type jobRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing JobClient + CallOptions **JobCallOptions +} + +// NewJobRESTClient creates a new job service rest client. +// +// A service handles job management, including job CRUD, enumeration and search. +func NewJobRESTClient(ctx context.Context, opts ...option.ClientOption) (*JobClient, error) { + clientOpts := append(defaultJobRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultJobRESTCallOptions() + c := &jobRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &JobClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultJobRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://jobs.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://jobs.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://jobs.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *jobRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *jobRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *jobRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *jobGRPCClient) CreateJob(ctx context.Context, req *talentpb.CreateJobRequest, opts ...gax.CallOption) (*talentpb.Job, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond) @@ -643,9 +778,692 @@ func (c *jobGRPCClient) GetOperation(ctx context.Context, req *longrunningpb.Get return resp, nil } +// CreateJob creates a new job. +// +// Typically, the job becomes searchable within 10 seconds, but it may take +// up to 5 minutes. +func (c *jobRESTClient) CreateJob(ctx context.Context, req *talentpb.CreateJobRequest, opts ...gax.CallOption) (*talentpb.Job, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v/jobs", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateJob[0:len((*c.CallOptions).CreateJob):len((*c.CallOptions).CreateJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &talentpb.Job{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// BatchCreateJobs begins executing a batch create jobs operation. +func (c *jobRESTClient) BatchCreateJobs(ctx context.Context, req *talentpb.BatchCreateJobsRequest, opts ...gax.CallOption) (*BatchCreateJobsOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v/jobs:batchCreate", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v4beta1/%s", resp.GetName()) + return &BatchCreateJobsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// GetJob retrieves the specified job, whose status is OPEN or recently EXPIRED +// within the last 90 days. +func (c *jobRESTClient) GetJob(ctx context.Context, req *talentpb.GetJobRequest, opts ...gax.CallOption) (*talentpb.Job, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetJob[0:len((*c.CallOptions).GetJob):len((*c.CallOptions).GetJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &talentpb.Job{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateJob updates specified job. +// +// Typically, updated contents become visible in search results within 10 +// seconds, but it may take up to 5 minutes. +func (c *jobRESTClient) UpdateJob(ctx context.Context, req *talentpb.UpdateJobRequest, opts ...gax.CallOption) (*talentpb.Job, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetJob().GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "job.name", url.QueryEscape(req.GetJob().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateJob[0:len((*c.CallOptions).UpdateJob):len((*c.CallOptions).UpdateJob)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &talentpb.Job{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// BatchUpdateJobs begins executing a batch update jobs operation. +func (c *jobRESTClient) BatchUpdateJobs(ctx context.Context, req *talentpb.BatchUpdateJobsRequest, opts ...gax.CallOption) (*BatchUpdateJobsOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v/jobs:batchUpdate", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v4beta1/%s", resp.GetName()) + return &BatchUpdateJobsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// DeleteJob deletes the specified job. +// +// Typically, the job becomes unsearchable within 10 seconds, but it may take +// up to 5 minutes. +func (c *jobRESTClient) DeleteJob(ctx context.Context, req *talentpb.DeleteJobRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// BatchDeleteJobs deletes a list of Jobs by filter. +func (c *jobRESTClient) BatchDeleteJobs(ctx context.Context, req *talentpb.BatchDeleteJobsRequest, opts ...gax.CallOption) error { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v/jobs:batchDelete", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// ListJobs lists jobs by filter. +func (c *jobRESTClient) ListJobs(ctx context.Context, req *talentpb.ListJobsRequest, opts ...gax.CallOption) *JobIterator { + it := &JobIterator{} + req = proto.Clone(req).(*talentpb.ListJobsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*talentpb.Job, string, error) { + resp := &talentpb.ListJobsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v/jobs", req.GetParent()) + + params := url.Values{} + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + if req.GetJobView() != 0 { + params.Add("jobView", fmt.Sprintf("%v", req.GetJobView())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetJobs(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// SearchJobs searches for jobs using the provided SearchJobsRequest. +// +// This call constrains the visibility of jobs +// present in the database, and only returns jobs that the caller has +// permission to search against. +func (c *jobRESTClient) SearchJobs(ctx context.Context, req *talentpb.SearchJobsRequest, opts ...gax.CallOption) (*talentpb.SearchJobsResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v/jobs:search", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SearchJobs[0:len((*c.CallOptions).SearchJobs):len((*c.CallOptions).SearchJobs)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &talentpb.SearchJobsResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// SearchJobsForAlert searches for jobs using the provided SearchJobsRequest. +// +// This API call is intended for the use case of targeting passive job +// seekers (for example, job seekers who have signed up to receive email +// alerts about potential job opportunities), and has different algorithmic +// adjustments that are targeted to passive job seekers. +// +// This call constrains the visibility of jobs +// present in the database, and only returns jobs the caller has +// permission to search against. +func (c *jobRESTClient) SearchJobsForAlert(ctx context.Context, req *talentpb.SearchJobsRequest, opts ...gax.CallOption) *SearchJobsResponse_MatchingJobIterator { + it := &SearchJobsResponse_MatchingJobIterator{} + req = proto.Clone(req).(*talentpb.SearchJobsRequest) + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*talentpb.SearchJobsResponse_MatchingJob, string, error) { + resp := &talentpb.SearchJobsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, "", err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v/jobs:searchForAlert", req.GetParent()) + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetMatchingJobs(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *jobRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // BatchCreateJobsOperation manages a long-running operation from BatchCreateJobs. type BatchCreateJobsOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // BatchCreateJobsOperation returns a new BatchCreateJobsOperation from a given name. @@ -656,10 +1474,21 @@ func (c *jobGRPCClient) BatchCreateJobsOperation(name string) *BatchCreateJobsOp } } +// BatchCreateJobsOperation returns a new BatchCreateJobsOperation from a given name. +// The name must be that of a previously created BatchCreateJobsOperation, possibly from a different process. +func (c *jobRESTClient) BatchCreateJobsOperation(name string) *BatchCreateJobsOperation { + override := fmt.Sprintf("/v4beta1/%s", name) + return &BatchCreateJobsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *BatchCreateJobsOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*talentpb.JobOperationResult, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp talentpb.JobOperationResult if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -677,6 +1506,7 @@ func (op *BatchCreateJobsOperation) Wait(ctx context.Context, opts ...gax.CallOp // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *BatchCreateJobsOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*talentpb.JobOperationResult, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp talentpb.JobOperationResult if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -714,7 +1544,8 @@ func (op *BatchCreateJobsOperation) Name() string { // BatchUpdateJobsOperation manages a long-running operation from BatchUpdateJobs. type BatchUpdateJobsOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // BatchUpdateJobsOperation returns a new BatchUpdateJobsOperation from a given name. @@ -725,10 +1556,21 @@ func (c *jobGRPCClient) BatchUpdateJobsOperation(name string) *BatchUpdateJobsOp } } +// BatchUpdateJobsOperation returns a new BatchUpdateJobsOperation from a given name. +// The name must be that of a previously created BatchUpdateJobsOperation, possibly from a different process. +func (c *jobRESTClient) BatchUpdateJobsOperation(name string) *BatchUpdateJobsOperation { + override := fmt.Sprintf("/v4beta1/%s", name) + return &BatchUpdateJobsOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *BatchUpdateJobsOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*talentpb.JobOperationResult, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp talentpb.JobOperationResult if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -746,6 +1588,7 @@ func (op *BatchUpdateJobsOperation) Wait(ctx context.Context, opts ...gax.CallOp // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *BatchUpdateJobsOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*talentpb.JobOperationResult, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp talentpb.JobOperationResult if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/talent/apiv4beta1/job_client_example_test.go b/talent/apiv4beta1/job_client_example_test.go index 2677fcd9f58a..29bf9ce60d3e 100644 --- a/talent/apiv4beta1/job_client_example_test.go +++ b/talent/apiv4beta1/job_client_example_test.go @@ -37,6 +37,18 @@ func ExampleNewJobClient() { _ = c } +func ExampleNewJobRESTClient() { + ctx := context.Background() + c, err := talent.NewJobRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleJobClient_CreateJob() { ctx := context.Background() c, err := talent.NewJobClient(ctx) diff --git a/talent/apiv4beta1/tenant_client.go b/talent/apiv4beta1/tenant_client.go index 58c9b76468d6..e1bb336cf1d0 100644 --- a/talent/apiv4beta1/tenant_client.go +++ b/talent/apiv4beta1/tenant_client.go @@ -17,22 +17,28 @@ package talent import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" talentpb "google.golang.org/genproto/googleapis/cloud/talent/v4beta1" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -104,6 +110,47 @@ func defaultTenantCallOptions() *TenantCallOptions { } } +func defaultTenantRESTCallOptions() *TenantCallOptions { + return &TenantCallOptions{ + CreateTenant: []gax.CallOption{}, + GetTenant: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + UpdateTenant: []gax.CallOption{}, + DeleteTenant: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + ListTenants: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + GetOperation: []gax.CallOption{}, + } +} + // internalTenantClient is an interface that defines the methods available from Cloud Talent Solution API. type internalTenantClient interface { Close() error @@ -264,6 +311,74 @@ func (c *tenantGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type tenantRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing TenantClient + CallOptions **TenantCallOptions +} + +// NewTenantRESTClient creates a new tenant service rest client. +// +// A service that handles tenant management, including CRUD and enumeration. +func NewTenantRESTClient(ctx context.Context, opts ...option.ClientOption) (*TenantClient, error) { + clientOpts := append(defaultTenantRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultTenantRESTCallOptions() + c := &tenantRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &TenantClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultTenantRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://jobs.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://jobs.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://jobs.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *tenantRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *tenantRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *tenantRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *tenantGRPCClient) CreateTenant(ctx context.Context, req *talentpb.CreateTenantRequest, opts ...gax.CallOption) (*talentpb.Tenant, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 30000*time.Millisecond) @@ -410,6 +525,352 @@ func (c *tenantGRPCClient) GetOperation(ctx context.Context, req *longrunningpb. return resp, nil } +// CreateTenant creates a new tenant entity. +func (c *tenantRESTClient) CreateTenant(ctx context.Context, req *talentpb.CreateTenantRequest, opts ...gax.CallOption) (*talentpb.Tenant, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v/tenants", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateTenant[0:len((*c.CallOptions).CreateTenant):len((*c.CallOptions).CreateTenant)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &talentpb.Tenant{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetTenant retrieves specified tenant. +func (c *tenantRESTClient) GetTenant(ctx context.Context, req *talentpb.GetTenantRequest, opts ...gax.CallOption) (*talentpb.Tenant, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetTenant[0:len((*c.CallOptions).GetTenant):len((*c.CallOptions).GetTenant)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &talentpb.Tenant{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// UpdateTenant updates specified tenant. +func (c *tenantRESTClient) UpdateTenant(ctx context.Context, req *talentpb.UpdateTenantRequest, opts ...gax.CallOption) (*talentpb.Tenant, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetTenant().GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "tenant.name", url.QueryEscape(req.GetTenant().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).UpdateTenant[0:len((*c.CallOptions).UpdateTenant):len((*c.CallOptions).UpdateTenant)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &talentpb.Tenant{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// DeleteTenant deletes specified tenant. +func (c *tenantRESTClient) DeleteTenant(ctx context.Context, req *talentpb.DeleteTenantRequest, opts ...gax.CallOption) error { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + // Returns nil if there is no error, otherwise wraps + // the response code and body into a non-nil error + return googleapi.CheckResponse(httpRsp) + }, opts...) +} + +// ListTenants lists all tenants associated with the project. +func (c *tenantRESTClient) ListTenants(ctx context.Context, req *talentpb.ListTenantsRequest, opts ...gax.CallOption) *TenantIterator { + it := &TenantIterator{} + req = proto.Clone(req).(*talentpb.ListTenantsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*talentpb.Tenant, string, error) { + resp := &talentpb.ListTenantsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v/tenants", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetTenants(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetOperation is a utility method from google.longrunning.Operations. +func (c *tenantRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v4beta1/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // TenantIterator manages a stream of *talentpb.Tenant. type TenantIterator struct { items []*talentpb.Tenant diff --git a/talent/apiv4beta1/tenant_client_example_test.go b/talent/apiv4beta1/tenant_client_example_test.go index 34f470dad1b5..e349f2285dfe 100644 --- a/talent/apiv4beta1/tenant_client_example_test.go +++ b/talent/apiv4beta1/tenant_client_example_test.go @@ -37,6 +37,18 @@ func ExampleNewTenantClient() { _ = c } +func ExampleNewTenantRESTClient() { + ctx := context.Background() + c, err := talent.NewTenantRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleTenantClient_CreateTenant() { ctx := context.Background() c, err := talent.NewTenantClient(ctx) diff --git a/videointelligence/apiv1beta2/doc.go b/videointelligence/apiv1beta2/doc.go index 2c504955b670..ed489a5c7d2e 100644 --- a/videointelligence/apiv1beta2/doc.go +++ b/videointelligence/apiv1beta2/doc.go @@ -78,6 +78,8 @@ package videointelligence // import "cloud.google.com/go/videointelligence/apiv1 import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -166,3 +168,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/videointelligence/apiv1beta2/gapic_metadata.json b/videointelligence/apiv1beta2/gapic_metadata.json index 48b64ef04a39..c784e40e621c 100644 --- a/videointelligence/apiv1beta2/gapic_metadata.json +++ b/videointelligence/apiv1beta2/gapic_metadata.json @@ -16,6 +16,16 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "AnnotateVideo": { + "methods": [ + "AnnotateVideo" + ] + } + } } } } diff --git a/videointelligence/apiv1beta2/video_intelligence_client.go b/videointelligence/apiv1beta2/video_intelligence_client.go index 4d0da3b1fb38..8060d61297f7 100644 --- a/videointelligence/apiv1beta2/video_intelligence_client.go +++ b/videointelligence/apiv1beta2/video_intelligence_client.go @@ -17,21 +17,29 @@ package videointelligence import ( + "bytes" "context" + "fmt" + "io/ioutil" "math" + "net/http" + "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" videointelligencepb "google.golang.org/genproto/googleapis/cloud/videointelligence/v1beta2" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newClientHook clientHook @@ -70,6 +78,22 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + AnnotateVideo: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 120000 * time.Millisecond, + Multiplier: 2.50, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + } +} + // internalClient is an interface that defines the methods available from Google Cloud Video Intelligence API. type internalClient interface { Close() error @@ -228,6 +252,89 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new video intelligence service rest client. +// +// Service that implements Google Cloud Video Intelligence API. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://videointelligence.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://videointelligence.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://videointelligence.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) AnnotateVideo(ctx context.Context, req *videointelligencepb.AnnotateVideoRequest, opts ...gax.CallOption) (*AnnotateVideoOperation, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) @@ -250,9 +357,74 @@ func (c *gRPCClient) AnnotateVideo(ctx context.Context, req *videointelligencepb }, nil } +// AnnotateVideo performs asynchronous video annotation. Progress and results can be +// retrieved through the google.longrunning.Operations interface. +// Operation.metadata contains AnnotateVideoProgress (progress). +// Operation.response contains AnnotateVideoResponse (results). +func (c *restClient) AnnotateVideo(ctx context.Context, req *videointelligencepb.AnnotateVideoRequest, opts ...gax.CallOption) (*AnnotateVideoOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta2/videos:annotate") + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta2/%s", resp.GetName()) + return &AnnotateVideoOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + // AnnotateVideoOperation manages a long-running operation from AnnotateVideo. type AnnotateVideoOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // AnnotateVideoOperation returns a new AnnotateVideoOperation from a given name. @@ -263,10 +435,21 @@ func (c *gRPCClient) AnnotateVideoOperation(name string) *AnnotateVideoOperation } } +// AnnotateVideoOperation returns a new AnnotateVideoOperation from a given name. +// The name must be that of a previously created AnnotateVideoOperation, possibly from a different process. +func (c *restClient) AnnotateVideoOperation(name string) *AnnotateVideoOperation { + override := fmt.Sprintf("/v1beta2/%s", name) + return &AnnotateVideoOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *AnnotateVideoOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*videointelligencepb.AnnotateVideoResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp videointelligencepb.AnnotateVideoResponse if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -284,6 +467,7 @@ func (op *AnnotateVideoOperation) Wait(ctx context.Context, opts ...gax.CallOpti // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *AnnotateVideoOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*videointelligencepb.AnnotateVideoResponse, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp videointelligencepb.AnnotateVideoResponse if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/videointelligence/apiv1beta2/video_intelligence_client_example_test.go b/videointelligence/apiv1beta2/video_intelligence_client_example_test.go index c4c3baf2b5dc..edc92a2d0c63 100644 --- a/videointelligence/apiv1beta2/video_intelligence_client_example_test.go +++ b/videointelligence/apiv1beta2/video_intelligence_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := videointelligence.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_AnnotateVideo() { ctx := context.Background() c, err := videointelligence.NewClient(ctx) diff --git a/videointelligence/go.mod b/videointelligence/go.mod index fb96a07070a3..464f0b4beef4 100644 --- a/videointelligence/go.mod +++ b/videointelligence/go.mod @@ -9,4 +9,5 @@ require ( google.golang.org/api v0.84.0 google.golang.org/genproto v0.0.0-20220621134657-43db42f103f7 google.golang.org/grpc v1.47.0 + google.golang.org/protobuf v1.28.0 ) diff --git a/vision/apiv1p1beta1/doc.go b/vision/apiv1p1beta1/doc.go index 663648d8069d..d8d3593ea9f9 100644 --- a/vision/apiv1p1beta1/doc.go +++ b/vision/apiv1p1beta1/doc.go @@ -73,6 +73,8 @@ package vision // import "cloud.google.com/go/vision/apiv1p1beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -162,3 +164,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/vision/apiv1p1beta1/gapic_metadata.json b/vision/apiv1p1beta1/gapic_metadata.json index 04778b0b3e36..4733f9ba7d2b 100644 --- a/vision/apiv1p1beta1/gapic_metadata.json +++ b/vision/apiv1p1beta1/gapic_metadata.json @@ -16,6 +16,16 @@ ] } } + }, + "rest": { + "libraryClient": "ImageAnnotatorClient", + "rpcs": { + "BatchAnnotateImages": { + "methods": [ + "BatchAnnotateImages" + ] + } + } } } } diff --git a/vision/apiv1p1beta1/image_annotator_client.go b/vision/apiv1p1beta1/image_annotator_client.go index 17b95ed63ab9..8622c2d47cf6 100644 --- a/vision/apiv1p1beta1/image_annotator_client.go +++ b/vision/apiv1p1beta1/image_annotator_client.go @@ -17,18 +17,26 @@ package vision import ( + "bytes" "context" + "fmt" + "io/ioutil" "math" + "net/http" + "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" visionpb "google.golang.org/genproto/googleapis/cloud/vision/v1p1beta1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newImageAnnotatorClientHook clientHook @@ -67,6 +75,22 @@ func defaultImageAnnotatorCallOptions() *ImageAnnotatorCallOptions { } } +func defaultImageAnnotatorRESTCallOptions() *ImageAnnotatorCallOptions { + return &ImageAnnotatorCallOptions{ + BatchAnnotateImages: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusServiceUnavailable, + http.StatusGatewayTimeout) + }), + }, + } +} + // internalImageAnnotatorClient is an interface that defines the methods available from Cloud Vision API. type internalImageAnnotatorClient interface { Close() error @@ -198,6 +222,76 @@ func (c *imageAnnotatorGRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type imageAnnotatorRESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing ImageAnnotatorClient + CallOptions **ImageAnnotatorCallOptions +} + +// NewImageAnnotatorRESTClient creates a new image annotator rest client. +// +// Service that performs Google Cloud Vision API detection tasks over client +// images, such as face, landmark, logo, label, and text detection. The +// ImageAnnotator service returns detected entities from the images. +func NewImageAnnotatorRESTClient(ctx context.Context, opts ...option.ClientOption) (*ImageAnnotatorClient, error) { + clientOpts := append(defaultImageAnnotatorRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultImageAnnotatorRESTCallOptions() + c := &imageAnnotatorRESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &ImageAnnotatorClient{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultImageAnnotatorRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://vision.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://vision.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://vision.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *imageAnnotatorRESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *imageAnnotatorRESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *imageAnnotatorRESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *imageAnnotatorGRPCClient) BatchAnnotateImages(ctx context.Context, req *visionpb.BatchAnnotateImagesRequest, opts ...gax.CallOption) (*visionpb.BatchAnnotateImagesResponse, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) @@ -217,3 +311,60 @@ func (c *imageAnnotatorGRPCClient) BatchAnnotateImages(ctx context.Context, req } return resp, nil } + +// BatchAnnotateImages run image detection and annotation for a batch of images. +func (c *imageAnnotatorRESTClient) BatchAnnotateImages(ctx context.Context, req *visionpb.BatchAnnotateImagesRequest, opts ...gax.CallOption) (*visionpb.BatchAnnotateImagesResponse, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1p1beta1/images:annotate") + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).BatchAnnotateImages[0:len((*c.CallOptions).BatchAnnotateImages):len((*c.CallOptions).BatchAnnotateImages)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &visionpb.BatchAnnotateImagesResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/vision/apiv1p1beta1/image_annotator_client_example_test.go b/vision/apiv1p1beta1/image_annotator_client_example_test.go index 5014af7c5261..5bd3f00cf030 100644 --- a/vision/apiv1p1beta1/image_annotator_client_example_test.go +++ b/vision/apiv1p1beta1/image_annotator_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewImageAnnotatorClient() { _ = c } +func ExampleNewImageAnnotatorRESTClient() { + ctx := context.Background() + c, err := vision.NewImageAnnotatorRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleImageAnnotatorClient_BatchAnnotateImages() { ctx := context.Background() c, err := vision.NewImageAnnotatorClient(ctx) diff --git a/webrisk/apiv1beta1/doc.go b/webrisk/apiv1beta1/doc.go index 2f3cfb8e6327..16f5aef49d89 100644 --- a/webrisk/apiv1beta1/doc.go +++ b/webrisk/apiv1beta1/doc.go @@ -69,6 +69,8 @@ package webrisk // import "cloud.google.com/go/webrisk/apiv1beta1" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -157,3 +159,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/webrisk/apiv1beta1/gapic_metadata.json b/webrisk/apiv1beta1/gapic_metadata.json index 75941f478c87..9c042e163dde 100644 --- a/webrisk/apiv1beta1/gapic_metadata.json +++ b/webrisk/apiv1beta1/gapic_metadata.json @@ -26,6 +26,26 @@ ] } } + }, + "rest": { + "libraryClient": "WebRiskServiceV1Beta1Client", + "rpcs": { + "ComputeThreatListDiff": { + "methods": [ + "ComputeThreatListDiff" + ] + }, + "SearchHashes": { + "methods": [ + "SearchHashes" + ] + }, + "SearchUris": { + "methods": [ + "SearchUris" + ] + } + } } } } diff --git a/webrisk/apiv1beta1/web_risk_service_v1_beta1_client.go b/webrisk/apiv1beta1/web_risk_service_v1_beta1_client.go index 8e163f5304f0..616a4fec8c8a 100644 --- a/webrisk/apiv1beta1/web_risk_service_v1_beta1_client.go +++ b/webrisk/apiv1beta1/web_risk_service_v1_beta1_client.go @@ -18,17 +18,24 @@ package webrisk import ( "context" + "fmt" + "io/ioutil" "math" + "net/http" + "net/url" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" webriskpb "google.golang.org/genproto/googleapis/cloud/webrisk/v1beta1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" ) var newWebRiskServiceV1Beta1ClientHook clientHook @@ -93,6 +100,44 @@ func defaultWebRiskServiceV1Beta1CallOptions() *WebRiskServiceV1Beta1CallOptions } } +func defaultWebRiskServiceV1Beta1RESTCallOptions() *WebRiskServiceV1Beta1CallOptions { + return &WebRiskServiceV1Beta1CallOptions{ + ComputeThreatListDiff: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + SearchUris: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + SearchHashes: []gax.CallOption{ + gax.WithRetry(func() gax.Retryer { + return gax.OnHTTPCodes(gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.30, + }, + http.StatusGatewayTimeout, + http.StatusServiceUnavailable) + }), + }, + } +} + // internalWebRiskServiceV1Beta1Client is an interface that defines the methods available from Web Risk API. type internalWebRiskServiceV1Beta1Client interface { Close() error @@ -238,6 +283,75 @@ func (c *webRiskServiceV1Beta1GRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type webRiskServiceV1Beta1RESTClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing WebRiskServiceV1Beta1Client + CallOptions **WebRiskServiceV1Beta1CallOptions +} + +// NewWebRiskServiceV1Beta1RESTClient creates a new web risk service v1 beta1 rest client. +// +// Web Risk v1beta1 API defines an interface to detect malicious URLs on your +// website and in client applications. +func NewWebRiskServiceV1Beta1RESTClient(ctx context.Context, opts ...option.ClientOption) (*WebRiskServiceV1Beta1Client, error) { + clientOpts := append(defaultWebRiskServiceV1Beta1RESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultWebRiskServiceV1Beta1RESTCallOptions() + c := &webRiskServiceV1Beta1RESTClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &WebRiskServiceV1Beta1Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultWebRiskServiceV1Beta1RESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://webrisk.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://webrisk.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://webrisk.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *webRiskServiceV1Beta1RESTClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *webRiskServiceV1Beta1RESTClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *webRiskServiceV1Beta1RESTClient) Connection() *grpc.ClientConn { + return nil +} func (c *webRiskServiceV1Beta1GRPCClient) ComputeThreatListDiff(ctx context.Context, req *webriskpb.ComputeThreatListDiffRequest, opts ...gax.CallOption) (*webriskpb.ComputeThreatListDiffResponse, error) { if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) @@ -297,3 +411,195 @@ func (c *webRiskServiceV1Beta1GRPCClient) SearchHashes(ctx context.Context, req } return resp, nil } + +// ComputeThreatListDiff gets the most recent threat list diffs. +func (c *webRiskServiceV1Beta1RESTClient) ComputeThreatListDiff(ctx context.Context, req *webriskpb.ComputeThreatListDiffRequest, opts ...gax.CallOption) (*webriskpb.ComputeThreatListDiffResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/threatLists:computeDiff") + + params := url.Values{} + if req.GetConstraints().GetMaxDatabaseEntries() != 0 { + params.Add("constraints.maxDatabaseEntries", fmt.Sprintf("%v", req.GetConstraints().GetMaxDatabaseEntries())) + } + if req.GetConstraints().GetMaxDiffEntries() != 0 { + params.Add("constraints.maxDiffEntries", fmt.Sprintf("%v", req.GetConstraints().GetMaxDiffEntries())) + } + if req.GetConstraints().GetSupportedCompressions() != nil { + params.Add("constraints.supportedCompressions", fmt.Sprintf("%v", req.GetConstraints().GetSupportedCompressions())) + } + params.Add("threatType", fmt.Sprintf("%v", req.GetThreatType())) + if req.GetVersionToken() != nil { + params.Add("versionToken", fmt.Sprintf("%v", req.GetVersionToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).ComputeThreatListDiff[0:len((*c.CallOptions).ComputeThreatListDiff):len((*c.CallOptions).ComputeThreatListDiff)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &webriskpb.ComputeThreatListDiffResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// SearchUris this method is used to check whether a URI is on a given threatList. +func (c *webRiskServiceV1Beta1RESTClient) SearchUris(ctx context.Context, req *webriskpb.SearchUrisRequest, opts ...gax.CallOption) (*webriskpb.SearchUrisResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/uris:search") + + params := url.Values{} + if req.GetThreatTypes() != nil { + params.Add("threatTypes", fmt.Sprintf("%v", req.GetThreatTypes())) + } + params.Add("uri", fmt.Sprintf("%v", req.GetUri())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SearchUris[0:len((*c.CallOptions).SearchUris):len((*c.CallOptions).SearchUris)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &webriskpb.SearchUrisResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// SearchHashes gets the full hashes that match the requested hash prefix. +// This is used after a hash prefix is looked up in a threatList +// and there is a match. The client side threatList only holds partial hashes +// so the client must query this method to determine if there is a full +// hash match of a threat. +func (c *webRiskServiceV1Beta1RESTClient) SearchHashes(ctx context.Context, req *webriskpb.SearchHashesRequest, opts ...gax.CallOption) (*webriskpb.SearchHashesResponse, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta1/hashes:search") + + params := url.Values{} + if req.GetHashPrefix() != nil { + params.Add("hashPrefix", fmt.Sprintf("%v", req.GetHashPrefix())) + } + if req.GetThreatTypes() != nil { + params.Add("threatTypes", fmt.Sprintf("%v", req.GetThreatTypes())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).SearchHashes[0:len((*c.CallOptions).SearchHashes):len((*c.CallOptions).SearchHashes)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &webriskpb.SearchHashesResponse{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} diff --git a/webrisk/apiv1beta1/web_risk_service_v1_beta1_client_example_test.go b/webrisk/apiv1beta1/web_risk_service_v1_beta1_client_example_test.go index f87732ae6006..2fcc8aee78e2 100644 --- a/webrisk/apiv1beta1/web_risk_service_v1_beta1_client_example_test.go +++ b/webrisk/apiv1beta1/web_risk_service_v1_beta1_client_example_test.go @@ -35,6 +35,18 @@ func ExampleNewWebRiskServiceV1Beta1Client() { _ = c } +func ExampleNewWebRiskServiceV1Beta1RESTClient() { + ctx := context.Background() + c, err := webrisk.NewWebRiskServiceV1Beta1RESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleWebRiskServiceV1Beta1Client_ComputeThreatListDiff() { ctx := context.Background() c, err := webrisk.NewWebRiskServiceV1Beta1Client(ctx) diff --git a/webrisk/go.mod b/webrisk/go.mod index 03e5c546a484..a040f0cae09a 100644 --- a/webrisk/go.mod +++ b/webrisk/go.mod @@ -8,4 +8,5 @@ require ( google.golang.org/api v0.84.0 google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90 google.golang.org/grpc v1.47.0 + google.golang.org/protobuf v1.28.0 ) diff --git a/workflows/apiv1beta/doc.go b/workflows/apiv1beta/doc.go index 2e307dbb132d..e1e7e1a570fc 100644 --- a/workflows/apiv1beta/doc.go +++ b/workflows/apiv1beta/doc.go @@ -78,6 +78,8 @@ package workflows // import "cloud.google.com/go/workflows/apiv1beta" import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -166,3 +168,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/workflows/apiv1beta/gapic_metadata.json b/workflows/apiv1beta/gapic_metadata.json index 78b97d5169f2..577c72b1c91e 100644 --- a/workflows/apiv1beta/gapic_metadata.json +++ b/workflows/apiv1beta/gapic_metadata.json @@ -36,6 +36,36 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "CreateWorkflow": { + "methods": [ + "CreateWorkflow" + ] + }, + "DeleteWorkflow": { + "methods": [ + "DeleteWorkflow" + ] + }, + "GetWorkflow": { + "methods": [ + "GetWorkflow" + ] + }, + "ListWorkflows": { + "methods": [ + "ListWorkflows" + ] + }, + "UpdateWorkflow": { + "methods": [ + "UpdateWorkflow" + ] + } + } } } } diff --git a/workflows/apiv1beta/workflows_client.go b/workflows/apiv1beta/workflows_client.go index 6d669b2a61ea..5cae664e4a98 100644 --- a/workflows/apiv1beta/workflows_client.go +++ b/workflows/apiv1beta/workflows_client.go @@ -17,23 +17,29 @@ package workflows import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" "time" "cloud.google.com/go/longrunning" lroauto "cloud.google.com/go/longrunning/autogen" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" workflowspb "google.golang.org/genproto/googleapis/cloud/workflows/v1beta" longrunningpb "google.golang.org/genproto/googleapis/longrunning" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -70,6 +76,16 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + ListWorkflows: []gax.CallOption{}, + GetWorkflow: []gax.CallOption{}, + CreateWorkflow: []gax.CallOption{}, + DeleteWorkflow: []gax.CallOption{}, + UpdateWorkflow: []gax.CallOption{}, + } +} + // internalClient is an interface that defines the methods available from Workflows API. type internalClient interface { Close() error @@ -276,6 +292,91 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // LROClient is used internally to handle long-running operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient **lroauto.OperationsClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new workflows rest client. +// +// Workflows is used to deploy and execute workflow programs. +// Workflows makes sure the program executes reliably, despite hardware and +// networking interruptions. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + lroOpts := []option.ClientOption{ + option.WithHTTPClient(httpClient), + option.WithEndpoint(endpoint), + } + opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...) + if err != nil { + return nil, err + } + c.LROClient = &opClient + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://workflows.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://workflows.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://workflows.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) ListWorkflows(ctx context.Context, req *workflowspb.ListWorkflowsRequest, opts ...gax.CallOption) *WorkflowIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -395,9 +496,362 @@ func (c *gRPCClient) UpdateWorkflow(ctx context.Context, req *workflowspb.Update }, nil } +// ListWorkflows lists Workflows in a given project and location. +// The default order is not specified. +func (c *restClient) ListWorkflows(ctx context.Context, req *workflowspb.ListWorkflowsRequest, opts ...gax.CallOption) *WorkflowIterator { + it := &WorkflowIterator{} + req = proto.Clone(req).(*workflowspb.ListWorkflowsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*workflowspb.Workflow, string, error) { + resp := &workflowspb.ListWorkflowsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/workflows", req.GetParent()) + + params := url.Values{} + if req.GetFilter() != "" { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req.GetOrderBy() != "" { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetWorkflows(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// GetWorkflow gets details of a single Workflow. +func (c *restClient) GetWorkflow(ctx context.Context, req *workflowspb.GetWorkflowRequest, opts ...gax.CallOption) (*workflowspb.Workflow, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetWorkflow[0:len((*c.CallOptions).GetWorkflow):len((*c.CallOptions).GetWorkflow)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &workflowspb.Workflow{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CreateWorkflow creates a new workflow. If a workflow with the specified name already +// exists in the specified project and location, the long running operation +// will return ALREADY_EXISTS error. +func (c *restClient) CreateWorkflow(ctx context.Context, req *workflowspb.CreateWorkflowRequest, opts ...gax.CallOption) (*CreateWorkflowOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetWorkflow() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/workflows", req.GetParent()) + + params := url.Values{} + params.Add("workflowId", fmt.Sprintf("%v", req.GetWorkflowId())) + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta/%s", resp.GetName()) + return &CreateWorkflowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// DeleteWorkflow deletes a workflow with the specified name. +// This method also cancels and deletes all running executions of the +// workflow. +func (c *restClient) DeleteWorkflow(ctx context.Context, req *workflowspb.DeleteWorkflowRequest, opts ...gax.CallOption) (*DeleteWorkflowOperation, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta/%s", resp.GetName()) + return &DeleteWorkflowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + +// UpdateWorkflow updates an existing workflow. +// Running this method has no impact on already running executions of the +// workflow. A new revision of the workflow may be created as a result of a +// successful update operation. In that case, such revision will be used +// in new workflow executions. +func (c *restClient) UpdateWorkflow(ctx context.Context, req *workflowspb.UpdateWorkflowRequest, opts ...gax.CallOption) (*UpdateWorkflowOperation, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetWorkflow() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetWorkflow().GetName()) + + params := url.Values{} + if req.GetUpdateMask().GetPaths() != nil { + params.Add("updateMask.paths", fmt.Sprintf("%v", req.GetUpdateMask().GetPaths())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "workflow.name", url.QueryEscape(req.GetWorkflow().GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &longrunningpb.Operation{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + + override := fmt.Sprintf("/v1beta/%s", resp.GetName()) + return &UpdateWorkflowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, resp), + pollPath: override, + }, nil +} + // CreateWorkflowOperation manages a long-running operation from CreateWorkflow. type CreateWorkflowOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // CreateWorkflowOperation returns a new CreateWorkflowOperation from a given name. @@ -408,10 +862,21 @@ func (c *gRPCClient) CreateWorkflowOperation(name string) *CreateWorkflowOperati } } +// CreateWorkflowOperation returns a new CreateWorkflowOperation from a given name. +// The name must be that of a previously created CreateWorkflowOperation, possibly from a different process. +func (c *restClient) CreateWorkflowOperation(name string) *CreateWorkflowOperation { + override := fmt.Sprintf("/v1beta/%s", name) + return &CreateWorkflowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *CreateWorkflowOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*workflowspb.Workflow, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp workflowspb.Workflow if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -429,6 +894,7 @@ func (op *CreateWorkflowOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *CreateWorkflowOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*workflowspb.Workflow, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp workflowspb.Workflow if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err @@ -466,7 +932,8 @@ func (op *CreateWorkflowOperation) Name() string { // DeleteWorkflowOperation manages a long-running operation from DeleteWorkflow. type DeleteWorkflowOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // DeleteWorkflowOperation returns a new DeleteWorkflowOperation from a given name. @@ -477,10 +944,21 @@ func (c *gRPCClient) DeleteWorkflowOperation(name string) *DeleteWorkflowOperati } } +// DeleteWorkflowOperation returns a new DeleteWorkflowOperation from a given name. +// The name must be that of a previously created DeleteWorkflowOperation, possibly from a different process. +func (c *restClient) DeleteWorkflowOperation(name string) *DeleteWorkflowOperation { + override := fmt.Sprintf("/v1beta/%s", name) + return &DeleteWorkflowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *DeleteWorkflowOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...) } @@ -494,6 +972,7 @@ func (op *DeleteWorkflowOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *DeleteWorkflowOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) return op.lro.Poll(ctx, nil, opts...) } @@ -524,7 +1003,8 @@ func (op *DeleteWorkflowOperation) Name() string { // UpdateWorkflowOperation manages a long-running operation from UpdateWorkflow. type UpdateWorkflowOperation struct { - lro *longrunning.Operation + lro *longrunning.Operation + pollPath string } // UpdateWorkflowOperation returns a new UpdateWorkflowOperation from a given name. @@ -535,10 +1015,21 @@ func (c *gRPCClient) UpdateWorkflowOperation(name string) *UpdateWorkflowOperati } } +// UpdateWorkflowOperation returns a new UpdateWorkflowOperation from a given name. +// The name must be that of a previously created UpdateWorkflowOperation, possibly from a different process. +func (c *restClient) UpdateWorkflowOperation(name string) *UpdateWorkflowOperation { + override := fmt.Sprintf("/v1beta/%s", name) + return &UpdateWorkflowOperation{ + lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}), + pollPath: override, + } +} + // Wait blocks until the long-running operation is completed, returning the response and any errors encountered. // // See documentation of Poll for error-handling information. func (op *UpdateWorkflowOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*workflowspb.Workflow, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp workflowspb.Workflow if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil { return nil, err @@ -556,6 +1047,7 @@ func (op *UpdateWorkflowOperation) Wait(ctx context.Context, opts ...gax.CallOpt // op.Done will return true, and the response of the operation is returned. // If Poll succeeds and the operation has not completed, the returned response and error are both nil. func (op *UpdateWorkflowOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*workflowspb.Workflow, error) { + opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...) var resp workflowspb.Workflow if err := op.lro.Poll(ctx, &resp, opts...); err != nil { return nil, err diff --git a/workflows/apiv1beta/workflows_client_example_test.go b/workflows/apiv1beta/workflows_client_example_test.go index 3238d479b0ef..54864005b94b 100644 --- a/workflows/apiv1beta/workflows_client_example_test.go +++ b/workflows/apiv1beta/workflows_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := workflows.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_ListWorkflows() { ctx := context.Background() c, err := workflows.NewClient(ctx) diff --git a/workflows/executions/apiv1beta/doc.go b/workflows/executions/apiv1beta/doc.go index d860c67dd8b3..9f4fde5f7f4e 100644 --- a/workflows/executions/apiv1beta/doc.go +++ b/workflows/executions/apiv1beta/doc.go @@ -77,6 +77,8 @@ package executions // import "cloud.google.com/go/workflows/executions/apiv1beta import ( "context" + "fmt" + "net/http" "os" "runtime" "strconv" @@ -165,3 +167,22 @@ func versionGo() string { } return "UNKNOWN" } + +// maybeUnknownEnum wraps the given proto-JSON parsing error if it is the result +// of receiving an unknown enum value. +func maybeUnknownEnum(err error) error { + if strings.Contains(err.Error(), "invalid value for enum type") { + err = fmt.Errorf("received an unknown enum value; a later version of the library may support it: %w", err) + } + return err +} + +// buildHeaders extracts metadata from the outgoing context, joins it with any other +// given metadata, and converts them into a http.Header. +func buildHeaders(ctx context.Context, mds ...metadata.MD) http.Header { + if cmd, ok := metadata.FromOutgoingContext(ctx); ok { + mds = append(mds, cmd) + } + md := metadata.Join(mds...) + return http.Header(md) +} diff --git a/workflows/executions/apiv1beta/executions_client.go b/workflows/executions/apiv1beta/executions_client.go index 1a27ff9d11b0..05381ec42870 100644 --- a/workflows/executions/apiv1beta/executions_client.go +++ b/workflows/executions/apiv1beta/executions_client.go @@ -17,19 +17,25 @@ package executions import ( + "bytes" "context" "fmt" + "io/ioutil" "math" + "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" gtransport "google.golang.org/api/transport/grpc" + httptransport "google.golang.org/api/transport/http" executionspb "google.golang.org/genproto/googleapis/cloud/workflows/executions/v1beta" "google.golang.org/grpc" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" ) @@ -64,6 +70,15 @@ func defaultCallOptions() *CallOptions { } } +func defaultRESTCallOptions() *CallOptions { + return &CallOptions{ + ListExecutions: []gax.CallOption{}, + CreateExecution: []gax.CallOption{}, + GetExecution: []gax.CallOption{}, + CancelExecution: []gax.CallOption{}, + } +} + // internalClient is an interface that defines the methods available from Workflow Executions API. type internalClient interface { Close() error @@ -214,6 +229,75 @@ func (c *gRPCClient) Close() error { return c.connPool.Close() } +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type restClient struct { + // The http endpoint to connect to. + endpoint string + + // The http client. + httpClient *http.Client + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions +} + +// NewRESTClient creates a new executions rest client. +// +// Executions is used to start and manage running instances of +// Workflows called executions. +func NewRESTClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := append(defaultRESTClientOptions(), opts...) + httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...) + if err != nil { + return nil, err + } + + callOpts := defaultRESTCallOptions() + c := &restClient{ + endpoint: endpoint, + httpClient: httpClient, + CallOptions: &callOpts, + } + c.setGoogleClientInfo() + + return &Client{internalClient: c, CallOptions: callOpts}, nil +} + +func defaultRESTClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("https://workflowexecutions.googleapis.com"), + internaloption.WithDefaultMTLSEndpoint("https://workflowexecutions.mtls.googleapis.com"), + internaloption.WithDefaultAudience("https://workflowexecutions.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + } +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *restClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN") + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *restClient) Close() error { + // Replace httpClient with nil to force cleanup. + c.httpClient = nil + return nil +} + +// Connection returns a connection to the API service. +// +// Deprecated. +func (c *restClient) Connection() *grpc.ClientConn { + return nil +} func (c *gRPCClient) ListExecutions(ctx context.Context, req *executionspb.ListExecutionsRequest, opts ...gax.CallOption) *ExecutionIterator { md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) @@ -310,6 +394,278 @@ func (c *gRPCClient) CancelExecution(ctx context.Context, req *executionspb.Canc return resp, nil } +// ListExecutions returns a list of executions which belong to the workflow with +// the given name. The method returns executions of all workflow +// revisions. Returned executions are ordered by their start time (newest +// first). +func (c *restClient) ListExecutions(ctx context.Context, req *executionspb.ListExecutionsRequest, opts ...gax.CallOption) *ExecutionIterator { + it := &ExecutionIterator{} + req = proto.Clone(req).(*executionspb.ListExecutionsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*executionspb.Execution, string, error) { + resp := &executionspb.ListExecutionsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, "", err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/executions", req.GetParent()) + + params := url.Values{} + if req.GetPageSize() != 0 { + params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize())) + } + if req.GetPageToken() != "" { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + headers := buildHeaders(ctx, c.xGoogMetadata, metadata.Pairs("Content-Type", "application/json")) + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, "", e + } + it.Response = resp + return resp.GetExecutions(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +// CreateExecution creates a new execution using the latest revision of the given workflow. +func (c *restClient) CreateExecution(ctx context.Context, req *executionspb.CreateExecutionRequest, opts ...gax.CallOption) (*executionspb.Execution, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + body := req.GetExecution() + jsonReq, err := m.Marshal(body) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v/executions", req.GetParent()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CreateExecution[0:len((*c.CallOptions).CreateExecution):len((*c.CallOptions).CreateExecution)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &executionspb.Execution{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// GetExecution returns an execution of the given name. +func (c *restClient) GetExecution(ctx context.Context, req *executionspb.GetExecutionRequest, opts ...gax.CallOption) (*executionspb.Execution, error) { + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v", req.GetName()) + + params := url.Values{} + if req.GetView() != 0 { + params.Add("view", fmt.Sprintf("%v", req.GetView())) + } + + baseUrl.RawQuery = params.Encode() + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).GetExecution[0:len((*c.CallOptions).GetExecution):len((*c.CallOptions).GetExecution)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &executionspb.Execution{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + +// CancelExecution cancels an execution of the given name. +func (c *restClient) CancelExecution(ctx context.Context, req *executionspb.CancelExecutionRequest, opts ...gax.CallOption) (*executionspb.Execution, error) { + m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true} + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, err + } + + baseUrl, err := url.Parse(c.endpoint) + if err != nil { + return nil, err + } + baseUrl.Path += fmt.Sprintf("/v1beta/%v:cancel", req.GetName()) + + // Build HTTP headers from client and context metadata. + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) + + headers := buildHeaders(ctx, c.xGoogMetadata, md, metadata.Pairs("Content-Type", "application/json")) + opts = append((*c.CallOptions).CancelExecution[0:len((*c.CallOptions).CancelExecution):len((*c.CallOptions).CancelExecution)], opts...) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + resp := &executionspb.Execution{} + e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + if settings.Path != "" { + baseUrl.Path = settings.Path + } + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return err + } + httpReq = httpReq.WithContext(ctx) + httpReq.Header = headers + + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return err + } + defer httpRsp.Body.Close() + + if err = googleapi.CheckResponse(httpRsp); err != nil { + return err + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return err + } + + if err := unm.Unmarshal(buf, resp); err != nil { + return maybeUnknownEnum(err) + } + + return nil + }, opts...) + if e != nil { + return nil, e + } + return resp, nil +} + // ExecutionIterator manages a stream of *executionspb.Execution. type ExecutionIterator struct { items []*executionspb.Execution diff --git a/workflows/executions/apiv1beta/executions_client_example_test.go b/workflows/executions/apiv1beta/executions_client_example_test.go index 9df5113f2775..90713fc41608 100644 --- a/workflows/executions/apiv1beta/executions_client_example_test.go +++ b/workflows/executions/apiv1beta/executions_client_example_test.go @@ -36,6 +36,18 @@ func ExampleNewClient() { _ = c } +func ExampleNewRESTClient() { + ctx := context.Background() + c, err := executions.NewRESTClient(ctx) + if err != nil { + // TODO: Handle error. + } + defer c.Close() + + // TODO: Use client. + _ = c +} + func ExampleClient_ListExecutions() { ctx := context.Background() c, err := executions.NewClient(ctx) diff --git a/workflows/executions/apiv1beta/gapic_metadata.json b/workflows/executions/apiv1beta/gapic_metadata.json index df3144a708a3..baaf947bb357 100644 --- a/workflows/executions/apiv1beta/gapic_metadata.json +++ b/workflows/executions/apiv1beta/gapic_metadata.json @@ -31,6 +31,31 @@ ] } } + }, + "rest": { + "libraryClient": "Client", + "rpcs": { + "CancelExecution": { + "methods": [ + "CancelExecution" + ] + }, + "CreateExecution": { + "methods": [ + "CreateExecution" + ] + }, + "GetExecution": { + "methods": [ + "GetExecution" + ] + }, + "ListExecutions": { + "methods": [ + "ListExecutions" + ] + } + } } } }