| // Copyright 2020 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| |
| package wire |
| |
| import ( |
| "fmt" |
| "regexp" |
| "strings" |
| ) |
| |
| // ValidateRegion verifies that the `input` string has the format of a valid |
| // Google Cloud region. An example region is "europe-west1". |
| // See https://cloud.google.com/compute/docs/regions-zones for more information. |
| func ValidateRegion(input string) error { |
| parts := strings.Split(input, "-") |
| if len(parts) != 2 { |
| return fmt.Errorf("pubsublite: invalid region %q", input) |
| } |
| return nil |
| } |
| |
| // LocationToRegion returns the region that the given location is in. |
| func LocationToRegion(location string) (string, error) { |
| parts := strings.Split(location, "-") |
| if len(parts) == 3 { |
| return strings.Join(parts[0:len(parts)-1], "-"), nil |
| } |
| if len(parts) == 2 { |
| return location, nil |
| } |
| return "", fmt.Errorf("pubsublite: location %q is not a valid zone or region", location) |
| } |
| |
| // LocationPath stores a path consisting of a project and zone/region. |
| type LocationPath struct { |
| // A Google Cloud project. The project ID (e.g. "my-project") or the project |
| // number (e.g. "987654321") can be provided. |
| Project string |
| |
| // A Google Cloud zone (e.g. "us-central1-a") or region (e.g. "us-central1"). |
| Location string |
| } |
| |
| func (l LocationPath) String() string { |
| return fmt.Sprintf("projects/%s/locations/%s", l.Project, l.Location) |
| } |
| |
| var locPathRE = regexp.MustCompile(`^projects/([^/]+)/locations/([^/]+)$`) |
| |
| // ParseLocationPath parses a project/location path. |
| func ParseLocationPath(input string) (LocationPath, error) { |
| parts := locPathRE.FindStringSubmatch(input) |
| if len(parts) < 3 { |
| return LocationPath{}, fmt.Errorf("pubsublite: invalid location path %q. valid format is %q", |
| input, "projects/PROJECT_ID/locations/ZONE") |
| } |
| return LocationPath{Project: parts[1], Location: parts[2]}, nil |
| } |
| |
| // TopicPath stores the full path of a Pub/Sub Lite topic. |
| type TopicPath struct { |
| // A Google Cloud project. The project ID (e.g. "my-project") or the project |
| // number (e.g. "987654321") can be provided. |
| Project string |
| |
| // A Google Cloud zone (e.g. "us-central1-a") or region (e.g. "us-central1"). |
| Location string |
| |
| // The ID of the Pub/Sub Lite topic, for example "my-topic-name". |
| TopicID string |
| } |
| |
| func (t TopicPath) String() string { |
| return fmt.Sprintf("projects/%s/locations/%s/topics/%s", t.Project, t.Location, t.TopicID) |
| } |
| |
| // LocationPath returns the topic's location path. |
| func (t TopicPath) LocationPath() LocationPath { |
| return LocationPath{Project: t.Project, Location: t.Location} |
| } |
| |
| var topicPathRE = regexp.MustCompile(`^projects/([^/]+)/locations/([^/]+)/topics/([^/]+)$`) |
| |
| // ParseTopicPath parses the full path of a Pub/Sub Lite topic. |
| func ParseTopicPath(input string) (TopicPath, error) { |
| parts := topicPathRE.FindStringSubmatch(input) |
| if len(parts) < 4 { |
| return TopicPath{}, fmt.Errorf("pubsublite: invalid topic path %q. valid format is %q", |
| input, "projects/PROJECT_ID/locations/ZONE_OR_REGION/topics/TOPIC_ID") |
| } |
| return TopicPath{Project: parts[1], Location: parts[2], TopicID: parts[3]}, nil |
| } |
| |
| // SubscriptionPath stores the full path of a Pub/Sub Lite subscription. |
| type SubscriptionPath struct { |
| // A Google Cloud project. The project ID (e.g. "my-project") or the project |
| // number (e.g. "987654321") can be provided. |
| Project string |
| |
| // A Google Cloud zone (e.g. "us-central1-a") or region (e.g. "us-central1"). |
| Location string |
| |
| // The ID of the Pub/Sub Lite subscription, for example |
| // "my-subscription-name". |
| SubscriptionID string |
| } |
| |
| func (s SubscriptionPath) String() string { |
| return fmt.Sprintf("projects/%s/locations/%s/subscriptions/%s", s.Project, s.Location, s.SubscriptionID) |
| } |
| |
| // LocationPath returns the subscription's location path. |
| func (s SubscriptionPath) LocationPath() LocationPath { |
| return LocationPath{Project: s.Project, Location: s.Location} |
| } |
| |
| var subsPathRE = regexp.MustCompile(`^projects/([^/]+)/locations/([^/]+)/subscriptions/([^/]+)$`) |
| |
| // ParseSubscriptionPath parses the full path of a Pub/Sub Lite subscription. |
| func ParseSubscriptionPath(input string) (SubscriptionPath, error) { |
| parts := subsPathRE.FindStringSubmatch(input) |
| if len(parts) < 4 { |
| return SubscriptionPath{}, fmt.Errorf("pubsublite: invalid subscription path %q. valid format is %q", |
| input, "projects/PROJECT_ID/locations/ZONE_OR_REGION/subscriptions/SUBSCRIPTION_ID") |
| } |
| return SubscriptionPath{Project: parts[1], Location: parts[2], SubscriptionID: parts[3]}, nil |
| } |
| |
| // ReservationPath stores the full path of a Pub/Sub Lite reservation. |
| type ReservationPath struct { |
| // A Google Cloud project. The project ID (e.g. "my-project") or the project |
| // number (e.g. "987654321") can be provided. |
| Project string |
| |
| // A Google Cloud region. An example region is "us-central1". |
| Region string |
| |
| // The ID of the Pub/Sub Lite reservation, for example "my-reservation-name". |
| ReservationID string |
| } |
| |
| func (r ReservationPath) String() string { |
| return fmt.Sprintf("projects/%s/locations/%s/reservations/%s", r.Project, r.Region, r.ReservationID) |
| } |
| |
| // Location returns the reservation's location path. |
| func (r ReservationPath) Location() LocationPath { |
| return LocationPath{Project: r.Project, Location: r.Region} |
| } |
| |
| var reservationPathRE = regexp.MustCompile(`^projects/([^/]+)/locations/([^/]+)/reservations/([^/]+)$`) |
| |
| // ParseReservationPath parses the full path of a Pub/Sub Lite reservation. |
| func ParseReservationPath(input string) (ReservationPath, error) { |
| parts := reservationPathRE.FindStringSubmatch(input) |
| if len(parts) < 4 { |
| return ReservationPath{}, fmt.Errorf("pubsublite: invalid reservation path %q. valid format is %q", |
| input, "projects/PROJECT_ID/locations/REGION/reservations/RESERVATION_ID") |
| } |
| return ReservationPath{Project: parts[1], Region: parts[2], ReservationID: parts[3]}, nil |
| } |
| |
| type topicPartition struct { |
| Path string |
| Partition int |
| } |
| |
| func (tp topicPartition) String() string { |
| return fmt.Sprintf("%s/partitions/%d", tp.Path, tp.Partition) |
| } |
| |
| type subscriptionPartition struct { |
| Path string |
| Partition int |
| } |
| |
| func (sp subscriptionPartition) String() string { |
| return fmt.Sprintf("%s/partitions/%d", sp.Path, sp.Partition) |
| } |
| |
| // MessageMetadata holds properties of a message published to the Pub/Sub Lite |
| // service. |
| // |
| // NOTE: This is duplicated in the pscompat package in order to generate nicer |
| // docs and should be kept consistent. |
| type MessageMetadata struct { |
| // The topic partition the message was published to. |
| Partition int |
| |
| // The offset the message was assigned. |
| Offset int64 |
| } |
| |
| func (m *MessageMetadata) String() string { |
| return fmt.Sprintf("%d:%d", m.Partition, m.Offset) |
| } |