Skip to content

Commit

Permalink
adding documentation for Ngrokit
Browse files Browse the repository at this point in the history
  • Loading branch information
leogdion committed Aug 27, 2024
1 parent d8d202a commit 156de90
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 88 deletions.
100 changes: 100 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Ngrokit

Swift API for Ngrok's Local API.

[![SwiftPM](https://img.shields.io/badge/SPM-Linux%20%7C%20iOS%20%7C%20macOS%20%7C%20watchOS%20%7C%20tvOS-success?logo=swift)](https://swift.org)
[![Twitter](https://img.shields.io/badge/[email protected]?style=flat)](http://twitter.com/brightdigit)
![GitHub](https://img.shields.io/github/license/brightdigit/Ngrokit)
![GitHub issues](https://img.shields.io/github/issues/brightdigit/Ngrokit)
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/brightdigit/Ngrokit/Ngrokit.yml?label=actions&logo=github&?branch=main)

[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fbrightdigit%2FNgrokit%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/brightdigit/Ngrokit)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fbrightdigit%2FNgrokit%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/brightdigit/Ngrokit)


<!--
[![Codecov](https://img.shields.io/codecov/c/github/brightdigit/Ngrokit)](https://codecov.io/gh/brightdigit/Ngrokit)
-->
[![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/brightdigit/Ngrokit)](https://www.codefactor.io/repository/github/brightdigit/Ngrokit)
[![codebeat badge](https://codebeat.co/badges/91d512f0-ab30-42f9-9791-02add3278171)](https://codebeat.co/projects/github-com-brightdigit-Ngrokit-main)
[![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/brightdigit/Ngrokit)](https://codeclimate.com/github/brightdigit/Ngrokit)
[![Code Climate technical debt](https://img.shields.io/codeclimate/tech-debt/brightdigit/Ngrokit?label=debt)](https://codeclimate.com/github/brightdigit/Ngrokit)
[![Code Climate issues](https://img.shields.io/codeclimate/issues/brightdigit/Ngrokit)](https://codeclimate.com/github/brightdigit/Ngrokit)
[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)

# Table of Contents

* [Introduction](#introduction)
* [Requirements](#requirements)
* [Installation](#installation)
* [Server Installation](#server-installation)
* [Client Installation](#client-installation)
* [Bonjour vs Ngrok](#bonjour-vs-ngrok)
* [Using Bonjour](#using-bonjour)
* [Using Ngrok](#using-ngrok)
* [License](#license)

# Requirements

**Apple Platforms**

- Xcode 16.0 or later
- Swift 6.0 or later
- iOS 17 / watchOS 10.0 / tvOS 17 / macOS 14 or later deployment targets

**Linux**

- Ubuntu 20.04 or later
- Swift 6.0 or later

# Installation

Sublimation has two components: Server and Client. You can check out the SublimationDemoApp Xcode project for an example.

To integrate **Sublimation** into your app using SPM, specify it in your Package.swift file:

```swift
let package = Package(
...
dependencies: [
.package(url: "https://github.com/brightdigit/Ngrokit.git", from: "1.0.0")
],
targets: [
.target(
name: "YourServerApp",
dependencies: [
.product(name: "Ngrokit", package: "Ngrokit"), ...
]),
...
]
)
```

# Usage

Ngrokit is an easy to use Swift library for call the local Ngrok API as well as running the `ngrok` command.

### Connecting to the Local REST API

Using the ``NgrokClient`` to connect to your local development server:

```swift
let client = NgrokClient(transport: URLSession.shared)
```

For using different transports see the client list at the [Swift OpenAPI Generator](https://github.com/apple/swift-openapi-generator?tab=readme-ov-file#package-ecosystem).

### Starting the CLI Process.

Start the CLI process by using ``NgrokProcessCLIAPI``:

```swift
let cliAPI = NgrokProcessCLIAPI(ngrokPath: "/usr/local/bin/ngrok")
let process = api.process(forHTTPPort: 100)
process.run { let error in
print(error)
}
```
# License

This code is distributed under the MIT license. See the [LICENSE](https://github.com/brightdigit/Ngrokit/LICENSE) file for more info.
57 changes: 57 additions & 0 deletions Sources/Ngrokit/Documentation.docc/Documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# ``Ngrokit``

Swift API for Ngrok's Local API.

## Overview

Ngrokit is an easy to use Swift library for call the local Ngrok API as well as running the `ngrok` command.

### Connecting to the Local REST API

Using the ``NgrokClient`` to connect to your local development server:

```swift
let client = NgrokClient(transport: URLSession.shared)
```

For using different transports see the client list at the [Swift OpenAPI Generator](https://github.com/apple/swift-openapi-generator?tab=readme-ov-file#package-ecosystem).

### Starting the CLI Process.

Start the CLI process by using ``NgrokProcessCLIAPI``:

```swift
let cliAPI = NgrokProcessCLIAPI(ngrokPath: "/usr/local/bin/ngrok")
let process = api.process(forHTTPPort: 100)
process.run { let error in
print(error)
}
```

## Topics

### Consuming Ngrok API

- ``NgrokClient``
- ``NgrokProcessCLIAPI``

### Data Structures

- ``NgrokTunnel``
- ``TunnelRequest``
- ``NgrokTunnelConfiguration``

### Errors

- ``RuntimeError``
- ``NgrokError``
- ``TerminationReason``

### Process Components

- ``NgrokProcess``
- ``NgrokCLIAPI``
- ``Processable``
- ``ProcessableProcess``
- ``Pipable``
- ``DataHandle``
14 changes: 0 additions & 14 deletions Sources/Ngrokit/NgrokCLIAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,6 @@
import Foundation

/// A protocol for interacting with the Ngrok CLI API.
///
/// This protocol extends the `Sendable` protocol.
///
/// - Note: The `Sendable` protocol is not defined in this code snippet.
///
/// - Important: The `NgrokCLIAPI` protocol is not defined in this code snippet.
///
/// - Requires: The `NgrokProcess` type to be defined.
///
/// - SeeAlso: `NgrokProcess`
public protocol NgrokCLIAPI: Sendable {
/// Creates a process for the specified HTTP port.
///
Expand All @@ -48,7 +38,3 @@ public protocol NgrokCLIAPI: Sendable {
/// - Returns: An instance of `NgrokProcess` for the specified port.
func process(forHTTPPort httpPort: Int) -> any NgrokProcess
}

/// A type representing a process created by the Ngrok CLI API.
///
/// - Note: The `NgrokProcess` type is not defined in this code snippet.
9 changes: 1 addition & 8 deletions Sources/Ngrokit/NgrokClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,12 @@ public import OpenAPIRuntime
/// To create an instance of `NgrokClient`,
/// you need to provide a transport and an optional server URL.
///
/// Example usage:
///
/// ```swift
/// let client = NgrokClient(transport: URLSession.shared)
/// ```
///
/// - Note: The default server URL is `try! Servers.server1()`.
///
/// - SeeAlso: `TunnelRequest`
/// - SeeAlso: `Tunnel`
public struct NgrokClient: Sendable {
// swift-format-ignore: NeverUseForceTry
/// The default server URL.
/// The default server URL which is `http://127.0.0.1:4040`N.
public static let defaultServerURL = try! Servers.server1()

private let underlyingClient: any APIProtocol
Expand Down
34 changes: 16 additions & 18 deletions Sources/Ngrokit/NgrokError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,40 +30,38 @@
public import Foundation

/// An enumeration representing possible errors that can occur with Ngrok.
///
/// - invalidMetadataLength: The metadata length is invalid.
/// - accountLimitExceeded: The account limit for simultaneous ngrok agent sessions has been exceeded.
/// - unsupportedAgentVersion: The ngrok agent version is no longer supported.
/// - captchaFailed: The captcha solving failed.
/// - accountViolation: Creating an ngrok account is disallowed due to violation of the terms of service.
/// - gatewayError: Ngrok gateway error.
/// - tunnelNotFound: The tunnel was not found.
/// - accountBanned: The account associated with the hostname has been banned.
/// - passwordTooShort: The password is too short.
/// - accountCreationNotAllowed: Creating a new account is not allowed.
/// - invalidCredentials: The email or password entered is not valid.
/// - userAlreadyExists: A user with the email address already exists.
/// - disallowedEmailProvider: Sign-ups are disallowed for the email provider.
/// - htmlContentSignupRequired: Signing up for an ngrok account and installing the authtoken is required before serving HTML content.
/// - websiteVisitWarning: A warning before visiting a website served by ngrok.com.
/// - tunnelConnectionFailed: The ngrok agent failed to establish a connection to the upstream web service.
///
public enum NgrokError: Int, LocalizedError {
/// The metadata length is invalid.
case invalidMetadataLength = 100
/// The account limit for simultaneous ngrok agent sessions has been exceeded.
case accountLimitExceeded = 108
/// The ngrok agent version is no longer supported.
case unsupportedAgentVersion = 120
/// The captcha solving failed.
case captchaFailed = 1_205
/// Creating an ngrok account is disallowed due to violation of the terms of service.
case accountViolation = 1_226
/// Ngrok gateway error.
case gatewayError = 3_004
/// The tunnel was not found.
case tunnelNotFound = 3_200
/// The account associated with the hostname has been banned.
case accountBanned = 3_208
/// The password is too short.
case passwordTooShort = 4_011
/// Creating a new account is not allowed.
case accountCreationNotAllowed = 4_013
/// The email or password entered is not valid.
case invalidCredentials = 4_100
/// A user with the email address already exists.
case userAlreadyExists = 4_101
/// Sign-ups are disallowed for the email provider.
case disallowedEmailProvider = 4_108
/// Signing up for an ngrok account and installing the authtoken is required before serving HTML content.
case htmlContentSignupRequired = 6_022
/// A warning before visiting a website served by ngrok.com.
case websiteVisitWarning = 6_024
/// The ngrok agent failed to establish a connection to the upstream web service.
case tunnelConnectionFailed = 8_012

/// A localized message describing what error occurred.
Expand Down
11 changes: 2 additions & 9 deletions Sources/Ngrokit/NgrokMacProcess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,8 @@ import Foundation
///
/// This class conforms to the `NgrokProcess` protocol.
///
/// - Note: This class is an actor,
/// meaning it can be safely accessed from multiple concurrent tasks.
///
/// - Author: Leo Dion
/// - Version: 2024
/// - Copyright: © BrightDigit
///
/// - SeeAlso: `NgrokProcess`
public actor NgrokMacProcess<ProcessType: Processable>: NgrokProcess {
internal actor NgrokMacProcess<ProcessType: Processable>: NgrokProcess {

private var terminationHandler: (@Sendable (any Error) -> Void)?
internal let process: ProcessType
Expand All @@ -53,7 +46,7 @@ public actor NgrokMacProcess<ProcessType: Processable>: NgrokProcess {
/// - ngrokPath: The path to the Ngrok executable.
/// - httpPort: The port to use for the HTTP connection.
/// - _: The type of process to use.
public init(ngrokPath: String, httpPort: Int, processType _: ProcessType.Type) {
public init(ngrokPath: String, httpPort: Int, processType: ProcessType.Type) {
self.init(process: .init(executableFilePath: ngrokPath, scheme: "http", port: httpPort))
}

Expand Down
13 changes: 1 addition & 12 deletions Sources/Ngrokit/NgrokProcess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,7 @@
// OTHER DEALINGS IN THE SOFTWARE.
//

/// A protocol representing a process for running Ngrok.
///
/// - Note: This protocol is `Sendable`, allowing it to be used in asynchronous contexts.
///
/// - Important: Implementations of this protocol
/// must provide a `run` method that runs the Ngrok process.
///
/// - Parameter onError: A closure to handle any errors that occur during the process.
///
/// - Throws: An error if the process fails to run.
///
/// - SeeAlso: `NgrokProcessImplementation`
/// A type representing a process created by the Ngrok CLI API.
public protocol NgrokProcess: Sendable {
/// Runs the Ngrok process.
///
Expand Down
17 changes: 8 additions & 9 deletions Sources/Ngrokit/NgrokProcessCLIAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,17 @@

import Foundation

/// A struct representing the Ngrok CLI API.
/// Starts the CLI app process.
///
/// Use this API to interact with Ngrok and create tunnels.
/// ```swift
/// let cliAPI = NgrokProcessCLIAPI(ngrokPath: "/usr/local/bin/ngrok")
/// let process = api.process(forHTTPPort: 100)
/// process.run { let error in
/// print(error)
/// }
/// ```
///
/// - Note: This API requires a valid Ngrok installation.
///
/// - Parameters:
/// - ngrokPath: The path to the Ngrok executable.
///
/// - SeeAlso: `NgrokCLIAPI`
public struct NgrokProcessCLIAPI<ProcessType: Processable> {
/// The path to the Ngrok executable.
public let ngrokPath: String
Expand All @@ -53,8 +54,6 @@ extension NgrokProcessCLIAPI: NgrokCLIAPI {
/// Creates a new `NgrokProcess` for the specified HTTP port.
///
/// - Parameter httpPort: The port number for the HTTP server.
///
/// - Returns: An instance of `NgrokProcess` for the specified HTTP port.
public func process(forHTTPPort httpPort: Int) -> any NgrokProcess {
NgrokMacProcess(ngrokPath: ngrokPath, httpPort: httpPort, processType: ProcessType.self)
}
Expand Down
9 changes: 1 addition & 8 deletions Sources/Ngrokit/NgrokTunnelConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,13 @@
// OTHER DEALINGS IN THE SOFTWARE.
//

/// Represents the configuration for an Ngrok tunnel.
///
/// - Note: This struct is `Sendable`.
///
/// - Parameters:
/// - addr: The URL of the tunnel.
/// - inspect: A boolean value indicating whether to enable inspection of the tunnel.
///
public import Foundation

#if canImport(FoundationNetworking)
public import FoundationNetworking
#endif

/// Represents the configuration for an Ngrok tunnel.
public struct NgrokTunnelConfiguration: Sendable {
/// The URL of the tunnel.
public let addr: URL
Expand Down
9 changes: 1 addition & 8 deletions Sources/Ngrokit/ProcessableProcess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,7 @@ public import Foundation

#if os(macOS)

/// A process that can be processed and executed.
///
/// - Note: This class is only available on macOS.
///
/// - Important: Make sure to set the `standardErrorPipe`
/// property before executing the process.
///
/// - SeeAlso: `Processable`
/// An abstract wrapper for `Process`.
public final class ProcessableProcess: Processable {

/// The type of pipe used for standard error.
Expand Down
9 changes: 7 additions & 2 deletions Sources/Ngrokit/RuntimeError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,17 @@
// OTHER DEALINGS IN THE SOFTWARE.
//

public import Foundation
import Foundation

/// Non-specific errors thrown by running the process or call the REST API.
public enum RuntimeError: Error {
/// Invalid URL from ``NgrokClient/startTunnel(_:)`` or ``NgrokClient/listTunnels()``
case invalidURL(String)
case invalidErrorData(Data)
/// Unknown error thrown during early process termination from ``NgrokProcess/run(onError:)``
case unknownEarlyTermination(String)
/// Unknown error.
case unknownError
/// Unknown Ngrok Error Code.
/// - SeeAlso: ``NgrokError``
case unknownNgrokErrorCode(Int)
}

0 comments on commit 156de90

Please sign in to comment.