1// Copyright 2020 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13
14package pubsublite
15
16import (
17	"fmt"
18	"regexp"
19	"strings"
20
21	"cloud.google.com/go/pubsublite/internal/wire"
22)
23
24// LocationPath stores a path consisting of a project and zone.
25type LocationPath struct {
26	// A Google Cloud project. The project ID (e.g. "my-project") or the project
27	// number (e.g. "987654321") can be provided.
28	Project string
29
30	// A Google Cloud zone, for example "us-central1-a".
31	// See https://cloud.google.com/pubsub/lite/docs/locations for the list of
32	// zones where Cloud Pub/Sub Lite is available.
33	Zone string
34}
35
36func (l LocationPath) String() string {
37	return fmt.Sprintf("projects/%s/locations/%s", l.Project, l.Zone)
38}
39
40// TopicPath stores the full path of a Cloud Pub/Sub Lite topic.
41// See https://cloud.google.com/pubsub/lite/docs/topics for more information.
42type TopicPath struct {
43	// A Google Cloud project. The project ID (e.g. "my-project") or the project
44	// number (e.g. "987654321") can be provided.
45	Project string
46
47	// A Google Cloud zone, for example "us-central1-a".
48	// See https://cloud.google.com/pubsub/lite/docs/locations for the list of
49	// zones where Cloud Pub/Sub Lite is available.
50	Zone string
51
52	// The ID of the Cloud Pub/Sub Lite topic, for example "my-topic-name".
53	// See https://cloud.google.com/pubsub/docs/admin#resource_names for more
54	// information.
55	TopicID string
56}
57
58func (t TopicPath) String() string {
59	return fmt.Sprintf("projects/%s/locations/%s/topics/%s", t.Project, t.Zone, t.TopicID)
60}
61
62func (t TopicPath) location() LocationPath {
63	return LocationPath{Project: t.Project, Zone: t.Zone}
64}
65
66var topicPathRE = regexp.MustCompile(`^projects/([^/]+)/locations/([^/]+)/topics/([^/]+)$`)
67
68// parseTopicPath parses the full path of a Cloud Pub/Sub Lite topic, which
69// should have the format: `projects/{project}/locations/{zone}/topics/{id}`.
70func parseTopicPath(input string) (TopicPath, error) {
71	parts := topicPathRE.FindStringSubmatch(input)
72	if len(parts) < 4 {
73		return TopicPath{}, fmt.Errorf("pubsublite: invalid topic path %q", input)
74	}
75	return TopicPath{Project: parts[1], Zone: parts[2], TopicID: parts[3]}, nil
76}
77
78// SubscriptionPath stores the full path of a Cloud Pub/Sub Lite subscription.
79// See https://cloud.google.com/pubsub/lite/docs/subscriptions for more
80// information.
81type SubscriptionPath struct {
82	// A Google Cloud project. The project ID (e.g. "my-project") or the project
83	// number (e.g. "987654321") can be provided.
84	Project string
85
86	// A Google Cloud zone. An example zone is "us-central1-a".
87	// See https://cloud.google.com/pubsub/lite/docs/locations for the list of
88	// zones where Cloud Pub/Sub Lite is available.
89	Zone string
90
91	// The ID of the Cloud Pub/Sub Lite subscription, for example
92	// "my-subscription-name".
93	// See https://cloud.google.com/pubsub/docs/admin#resource_names for more
94	// information.
95	SubscriptionID string
96}
97
98func (s SubscriptionPath) String() string {
99	return fmt.Sprintf("projects/%s/locations/%s/subscriptions/%s", s.Project, s.Zone, s.SubscriptionID)
100}
101
102func (s SubscriptionPath) location() LocationPath {
103	return LocationPath{Project: s.Project, Zone: s.Zone}
104}
105
106var subsPathRE = regexp.MustCompile(`^projects/([^/]+)/locations/([^/]+)/subscriptions/([^/]+)$`)
107
108// parseSubscriptionPath parses the full path of a Cloud Pub/Sub Lite
109// subscription, which should have the format:
110// `projects/{project}/locations/{zone}/subscriptions/{id}`.
111func parseSubscriptionPath(input string) (SubscriptionPath, error) {
112	parts := subsPathRE.FindStringSubmatch(input)
113	if len(parts) < 4 {
114		return SubscriptionPath{}, fmt.Errorf("pubsublite: invalid subscription path %q", input)
115	}
116	return SubscriptionPath{Project: parts[1], Zone: parts[2], SubscriptionID: parts[3]}, nil
117}
118
119// ZoneToRegion returns the region that the given zone is in.
120func ZoneToRegion(zone string) (string, error) {
121	if err := wire.ValidateZone(zone); err != nil {
122		return "", err
123	}
124	return zone[0:strings.LastIndex(zone, "-")], nil
125}
126