Skip to content

Commit

Permalink
Move the pcap example into Source/Examples/ (#1119)
Browse files Browse the repository at this point in the history
Motivation:

The PCAP example depends on swift-nio-extras. Since grpc-swift now
depends on swift-nio-extras (and we have target based dependency
resolution) the example can live in-source with other examples.

Modifications:

- Move Examples/PCAPExample to Source/Examples/PacketCapture.
- Make it a target in the GRPC package, rather than its own package.

Result:

Easier to avoid bit-rot.
  • Loading branch information
glbrntt authored Feb 1, 2021
1 parent c85a7ef commit 34c984c
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 110 deletions.
7 changes: 0 additions & 7 deletions Examples/PCAPExample/.gitignore

This file was deleted.

34 changes: 0 additions & 34 deletions Examples/PCAPExample/Package.swift

This file was deleted.

1 change: 0 additions & 1 deletion Examples/PCAPExample/Sources/PCAPExample/echo.grpc.swift

This file was deleted.

1 change: 0 additions & 1 deletion Examples/PCAPExample/Sources/PCAPExample/echo.pb.swift

This file was deleted.

5 changes: 0 additions & 5 deletions Examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ Samples that call Google gRPC APIs are in the [Google](Google) directory.
[EchoWeb](EchoWeb) is an example which uses a JavaScript client to communicate
with a gRPC Server using the gRPC-Web protocol.

## PCAP

[PCAPExample](PCAPExample) demonstrates how to configure a client to use a
debug channel initializer which writes *.pcap* files.

## Other Examples

See also:
Expand Down
13 changes: 13 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -257,5 +257,18 @@ let package = Package(
],
path: "Sources/Examples/RouteGuide/Server"
),

// Client for the PacketCapture example
.target(
name: "PacketCapture",
dependencies: [
.target(name: "GRPC"),
.target(name: "EchoModel"),
.product(name: "NIO", package: "swift-nio"),
.product(name: "NIOExtras", package: "swift-nio-extras"),
.product(name: "ArgumentParser", package: "swift-argument-parser"),
],
path: "Sources/Examples/PacketCapture"
),
]
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,17 @@ tools like [Wireshark][wireshark] or `tcpdump`.

## Running the Example

The example relies on the Echo server from the gRPC Swift repository. To start
the server, from the **root of the gRPC repository** run:
The example relies on the Echo server from a different example. To start the
server run:

```sh
$ swift run Echo server 0
$ swift run Echo server
```

Note the port printed by the server. In a separate shell, in **this** directory
run:
In a separate shell run:

```sh
$ swift run PCAPExample localhost <SERVER_PORT>
$ swift run PacketCapture
```

Some logs should be emitted similar to below, including the path of the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ArgumentParser
import Dispatch
import EchoModel
import GRPC
import Logging
import NIO
import NIOExtras

// Parse the command line args.
var args = CommandLine.arguments
guard args.count == 3, let port = Int(args[2]) else {
let usage = """
Usage: \(args[0]) SERVER_HOST SERVER_PORT
Note: you can start a server from the root of the gRPC Swift directory by running:
$ swift run Echo server 0
"""
print(usage)
exit(1)
}

let host = args[1]

// Create a logger.
let logger = Logger(label: "gRPC PCAP Demo")

Expand Down Expand Up @@ -96,50 +82,59 @@ func addPCAPHandler(toChannel channel: Channel) -> EventLoopFuture<Void> {
}
}

// Create an `EventLoopGroup`.
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
defer {
try! group.syncShutdownGracefully()
}
struct PCAP: ParsableCommand {
@Option(help: "The port to connect to")
var port = 1234

// Create a channel.
let channel = ClientConnection.insecure(group: group)
// Set the debug initializer: it will add a handler to each created channel to write a PCAP when
// the channel is closed.
.withDebugChannelInitializer(addPCAPHandler(toChannel:))
// We're connecting to our own server here; we'll disable connection re-establishment.
.withConnectionReestablishment(enabled: false)
// Connect!
.connect(host: host, port: port)

// Create a client.
let echo = Echo_EchoClient(channel: channel)

// Start an RPC.
let update = echo.update { response in
logger.info("Received response '\(response.text)'")
}
func run() throws {
// Create an `EventLoopGroup`.
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
defer {
try! group.syncShutdownGracefully()
}

// Send some requests.
for text in ["foo", "bar", "baz", "thud", "grunt", "gorp"] {
update.sendMessage(.with { $0.text = text }).whenSuccess {
logger.info("Sent request '\(text)'")
}
}
// Create a channel.
let channel = ClientConnection.insecure(group: group)
// Set the debug initializer: it will add a handler to each created channel to write a PCAP when
// the channel is closed.
.withDebugChannelInitializer(addPCAPHandler(toChannel:))
// We're connecting to our own server here; we'll disable connection re-establishment.
.withConnectionReestablishment(enabled: false)
// Connect!
.connect(host: "localhost", port: self.port)

// Create a client.
let echo = Echo_EchoClient(channel: channel)

// Start an RPC.
let update = echo.update { response in
logger.info("Received response '\(response.text)'")
}

// Close the request stream.
update.sendEnd(promise: nil)
// Send some requests.
for text in ["foo", "bar", "baz", "thud", "grunt", "gorp"] {
update.sendMessage(.with { $0.text = text }).whenSuccess {
logger.info("Sent request '\(text)'")
}
}

// Close the request stream.
update.sendEnd(promise: nil)

// Once the RPC finishes close the connection.
let closed = update.status.flatMap { status -> EventLoopFuture<Void> in
if status.isOk {
logger.info("✅ RPC completed successfully")
} else {
logger.error("💥 RPC failed with status '\(status)'")
}
logger.info("Closing channel")
return channel.close()
}

// Once the RPC finishes close the connection.
let closed = update.status.flatMap { status -> EventLoopFuture<Void> in
if status.isOk {
logger.info("✅ RPC completed successfully")
} else {
logger.error("💥 RPC failed with status '\(status)'")
// Wait for the channel to be closed.
try closed.wait()
}
logger.info("Closing channel")
return channel.close()
}

// Wait for the channel to be closed.
try closed.wait()
PCAP.main()

0 comments on commit 34c984c

Please sign in to comment.