Skip to content

Commit

Permalink
Merge pull request #31 from Clearcals/susheel/master/pubsub_setup
Browse files Browse the repository at this point in the history
Added support for Google PubSub
  • Loading branch information
Andrewangeta authored Aug 4, 2021
2 parents dfdfe97 + 7d2c717 commit cc2b048
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 1 deletion.
12 changes: 11 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ let package = Package(
.library(
name: "CloudTranslation",
targets: ["CloudTranslation"]),
.library(
name: "CloudPubSub",
targets: ["CloudPubSub"]),
],
dependencies: [
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0"),
.package(url: "https://github.com/vapor-community/google-cloud-kit.git", from: "1.0.0-rc")
.package(url: "https://github.com/vapor-community/google-cloud-kit.git", from: "1.0.0-rc.7")
],
targets: [
.target(
Expand Down Expand Up @@ -64,5 +67,12 @@ let package = Package(
.product(name: "GoogleCloudTranslation", package: "google-cloud-kit"),
.target(name: "GoogleCloud")
]),
.target(
name: "CloudPubSub",
dependencies: [
.product(name: "Vapor", package: "vapor"),
.product(name: "GoogleCloudPubSub", package: "google-cloud-kit"),
.target(name: "GoogleCloud")
]),
]
)
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,7 @@ You can check each supported API's README for a getting started guide.

[x] [CloudTranslation](/Sources/CloudTranslation/README.md)

[x] [CloudPubSub](/Sources/CloudPubSub/README.md)

### A More detailed guide can be found [here](https://github.com/vapor-community/google-cloud-kit).

111 changes: 111 additions & 0 deletions Sources/CloudPubSub/GoogleCloudPubSubAPI.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//
// GoogleCloudPubSubAPI.swift
//
//
// Created by Susheel Athmakuri on 6/20/21.
//

import Vapor
@_exported import PubSub
@_exported import GoogleCloud

extension Application.GoogleCloudPlatform {
private struct CloudPubSubAPIKey: StorageKey {
typealias Value = GoogleCloudPubSubAPI
}

private struct CloudPubSubConfigurationKey: StorageKey {
typealias Value = GoogleCloudPubSubConfiguration
}

private struct CloudSPubSubHTTPClientKey: StorageKey, LockKey {
typealias Value = HTTPClient
}

public var pubsub: GoogleCloudPubSubAPI {
get {
if let existing = self.application.storage[CloudPubSubAPIKey.self] {
return existing
} else {
return .init(application: self.application,
eventLoop: self.application.eventLoopGroup.next())
}
}

nonmutating set {
self.application.storage[CloudPubSubAPIKey.self] = newValue
}
}

public struct GoogleCloudPubSubAPI {
public let application: Application
public let eventLoop: EventLoop

/// A client used to interact with the `GoogleCloudPubSub` API.
public var client: GoogleCloudPubSubClient {
do {
let new = try GoogleCloudPubSubClient(credentials: self.application.googleCloud.credentials, config: self.configuration, httpClient: self.http, eventLoop: self.eventLoop)
return new
} catch {
fatalError("\(error.localizedDescription)")
}
}

/// The configuration for using `GoogleCloudPubSub` APIs.
public var configuration: GoogleCloudPubSubConfiguration {
get {
if let configuration = application.storage[CloudPubSubConfigurationKey.self] {
return configuration
} else {
fatalError("Cloud PubSub configuration has not been set. Use app.googleCloud.pubsub.configuration = ...")
}
}
set {
if application.storage[CloudPubSubConfigurationKey.self] == nil {
application.storage[CloudPubSubConfigurationKey.self] = newValue
} else {
fatalError("Attempting to override credentials configuration after being set is not allowed.")
}
}
}

/// Custom `HTTPClient` that ignores unclean SSL shutdown.
public var http: HTTPClient {
if let existing = application.storage[CloudSPubSubHTTPClientKey.self] {
return existing
} else {
let lock = application.locks.lock(for: CloudSPubSubHTTPClientKey.self)
lock.lock()
defer { lock.unlock() }
if let existing = application.storage[CloudSPubSubHTTPClientKey.self] {
return existing
}
let new = HTTPClient(
eventLoopGroupProvider: .shared(application.eventLoopGroup),
configuration: HTTPClient.Configuration(ignoreUncleanSSLShutdown: true)
)
application.storage.set(CloudSPubSubHTTPClientKey.self, to: new) {
try $0.syncShutdown()
}
return new
}
}
}
}

extension Request {
private struct GoogleCloudPubSubKey: StorageKey {
typealias Value = GoogleCloudPubSubClient
}

/// A client used to interact with the `GoogleCloudPubSub` API
public var gcPubSub: GoogleCloudPubSubClient {
if let existing = application.storage[GoogleCloudPubSubKey.self] {
return existing.hopped(to: self.eventLoop)
} else {
let new = Application.GoogleCloudPlatform.GoogleCloudPubSubAPI(application: self.application, eventLoop: self.eventLoop).client
application.storage[GoogleCloudPubSubKey.self] = new
return new
}
}
}
64 changes: 64 additions & 0 deletions Sources/CloudPubSub/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# GoogleCloudPubSubAPI

## Getting Started
If you only need to use the [Google Cloud PubSub API](https://cloud.google.com/pubsub), then this guide will help you get started.

In your `Package.swift` file, make sure you have the following dependencies and targets

```swift
dependencies: [
//...
.package(url: "https://github.com/vapor-community/google-cloud.git", from: "1.0.0"),
],
targets: [
.target(name: "MyAppName", dependencies: [
//...
.product(name: "CloudPubSub", package: "google-cloud"),
]),
]
```

Now you can setup the configuration for any GCP API globally via `Application`.

In `configure.swift`

```swift
import CloudPubSub

app.googleCloud.credentials = try GoogleCloudCredentialsConfiguration(projectId: "myprojectid-12345",
credentialsFile: "~/path/to/service-account.json")
```
Next we setup the CloudlPubSub API configuration (specific to this API).

```swift
app.googleCloud.pubsub.configuration = .default()
```

Now we can start using the GoogleCloudPubSub API
There's a handy extension on `Request` that you can use to get access to a pubsub client via a property named `gcPubsub`.

```swift
func publishMessage(_ req: Request) throws -> EventLoopFuture<[String]> {
guard let topicId = req.parameters.get("topicId") else {
throw Abort(.badRequest, reason:"Missing Topic ID from the request")
}

try PubSubMessage.validate(content: req)
let message = try req.content.decode(PubSubMessage.self)

return req.gcPubSub.pubSubTopic.publish(topicId: topicId,
data: message.data,
attributes: nil,
orderingKey: nil)
.map { response in
return response.messageIds
}
}

struct PubSubMessage: Content {
let data: String
let attributes: [String: String]?
let orderingKey: String?
}
```

0 comments on commit cc2b048

Please sign in to comment.