Skip to content

Commit

Permalink
Merge pull request #11 from 1711-Games/upgrade-5.9
Browse files Browse the repository at this point in the history
Upgrade to 5.9
  • Loading branch information
kirilltitov authored Oct 5, 2023
2 parents 339137f + 562752e commit 19b44af
Show file tree
Hide file tree
Showing 14 changed files with 108 additions and 131 deletions.
4 changes: 1 addition & 3 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.5
// swift-tools-version:5.9

import PackageDescription

Expand All @@ -24,7 +24,6 @@ let package = Package(

// used by LGNP
.package(url: "https://github.com/apple/swift-crypto.git", from: "1.1.7"),
.package(name: "Gzip", url: "https://github.com/1024jp/GzipSwift.git", from: "5.1.1"),
],
targets: [
.target(
Expand All @@ -40,7 +39,6 @@ let package = Package(
name: "LGNP",
dependencies: [
"LGNCore",
"Gzip",
.product(name: "Crypto", package: "swift-crypto"),
],
exclude: ["README.md", "logo.png"]
Expand Down
89 changes: 0 additions & 89 deletions Sources/LGNC/Contracts/AnyContact.swift

This file was deleted.

84 changes: 82 additions & 2 deletions Sources/LGNC/Contracts/Contract.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import LGNLog
import Entita
import NIO

/// A type erased yet more concrete contract than `AnyContract`, as it defines `Request`, `Response` and other dynamic stuff
public protocol Contract: AnyContract {
public typealias Meta = LGNC.Entity.Meta
public typealias CanonicalCompositeRequest = Swift.Result<Entity, Error>
public typealias CanonicalStructuredContractResponse = (response: Entity, meta: Meta)

public protocol Contract {
/// Request type of contract
associatedtype Request: ContractEntity

Expand All @@ -14,6 +17,39 @@ public protocol Contract: AnyContract {
/// Service to which current contract belongs to
associatedtype ParentService: Service

/// Canonical form of contract body (guarantee) type
typealias CanonicalGuaranteeBody = (CanonicalCompositeRequest) async throws -> ContractExecutionResult

/// URI of contract, must be unique for service
static var URI: String { get }

/// Indicates whether contract can be invoked with HTTP GET method (and respective GET params)
static var isGETSafe: Bool { get }

/// Allowed transports for contract, must not be empty
static var transports: [LGNCore.Transport] { get }

/// Preferred transport to be used by client if no transport is provided, see default implementation
static var preferredTransport: LGNCore.Transport { get }

/// Allowed content types of request for contract, must not be empty
static var contentTypes: [LGNCore.ContentType] { get }

/// Preferred content type of request for contract, see default implementation
static var preferredContentType: LGNCore.ContentType { get }

/// Indicates whether this contract returns response in structured form (i.e. an API contract in JSON/MsgPack format)
static var isResponseStructured: Bool { get }

/// A computed property returning `true` if contract is guaranteed
static var isGuaranteed: Bool { get }

/// Contract guarantee closure body (must not be set directly)
static var _guaranteeBody: Optional<Self.CanonicalGuaranteeBody> { get set }

/// An internal method for invoking contract with given raw dict (context is available via `LGNCore.Context.current`), not to be used directly
static func _invoke(with dict: Entita.Dict) async throws -> ContractExecutionResult

/// Executes current contract on remote node at given address with given request
static func executeReturningMeta(
at address: LGNCore.Address,
Expand All @@ -32,6 +68,50 @@ public protocol Contract: AnyContract {
}

public extension Contract {
static var isResponseStructured: Bool {
true
}

static var isWebSocketTransportAvailable: Bool {
self.transports.contains(.WebSocket)
}

static var isWebSocketOnly: Bool {
self.transports == [.WebSocket]
}

static var isGETSafe: Bool { false }

static var preferredTransport: LGNCore.Transport {
guard self.transports.count > 0 else {
Logger.current.error("Empty transports in contract \(Self.self), returning .LGNS")
return .LGNS
}

if self.transports.contains(.LGNS) {
return .LGNS
}

return .HTTP
}

static var preferredContentType: LGNCore.ContentType {
guard self.transports.count > 0 else {
Logger.current.error("Empty content-types in contract \(Self.self), returning .JSON")
return .JSON
}

if Self.preferredTransport == .LGNS && self.contentTypes.contains(.MsgPack) {
return .MsgPack
}

return .JSON
}

static var isGuaranteed: Bool {
self._guaranteeBody != nil
}

static func _invoke(with dict: Entita.Dict) async throws -> ContractExecutionResult {
guard let guaranteeBody = self._guaranteeBody else {
throw LGNC.E.ControllerError("No guarantee closure for contract '\(self.URI)'")
Expand Down
2 changes: 1 addition & 1 deletion Sources/LGNC/HTTP/HTTP+AnyServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import NIOHTTP1
import AsyncHTTPClient

public extension LGNC.HTTP {
class Server: AnyServer, @unchecked Sendable {
class Server: LGNCoreServer, @unchecked Sendable {
private let readTimeout: TimeAmount
private let writeTimeout: TimeAmount

Expand Down
6 changes: 4 additions & 2 deletions Sources/LGNC/LGNC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import LGNP
import LGNS
import NIO

public typealias Server = LGNCoreServer

public enum LGNC {
public static let VERSION = "0.9.9.9"

Expand Down Expand Up @@ -64,7 +66,7 @@ public enum LGNC {
eventLoopGroup: EventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount),
readTimeout: TimeAmount = .minutes(1),
writeTimeout: TimeAmount = .minutes(1)
) async throws -> AnyServer {
) async throws -> some Server {
try await S.startServerHTTP(
at: target,
eventLoopGroup: eventLoopGroup,
Expand All @@ -82,7 +84,7 @@ public enum LGNC {
requiredBitmask: LGNP.Message.ControlBitmask = .defaultValues,
readTimeout: TimeAmount = .seconds(1),
writeTimeout: TimeAmount = .seconds(1)
) async throws -> AnyServer {
) async throws -> some Server {
try await S.startServerLGNS(
at: target,
cryptor: cryptor,
Expand Down
6 changes: 3 additions & 3 deletions Sources/LGNC/Server/Server+HTTP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public extension Service {
webSocketRouter: WebsocketRouter.Type? = nil,
readTimeout: TimeAmount = .minutes(1),
writeTimeout: TimeAmount = .minutes(1)
) throws -> AnyServer {
) throws -> some Server {
try self.validate(transport: .HTTP)
try self.checkGuarantees()

Expand Down Expand Up @@ -184,8 +184,8 @@ public extension Service {
eventLoopGroup: EventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount),
readTimeout: TimeAmount = .minutes(1),
writeTimeout: TimeAmount = .minutes(1)
) async throws -> AnyServer {
let server: AnyServer = try self.getServerHTTP(
) async throws -> some Server {
let server: some Server = try self.getServerHTTP(
at: target,
eventLoopGroup: eventLoopGroup,
readTimeout: readTimeout,
Expand Down
6 changes: 3 additions & 3 deletions Sources/LGNC/Server/Server+LGNS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public extension Service {
requiredBitmask: LGNP.Message.ControlBitmask = .defaultValues,
readTimeout: TimeAmount = .minutes(1),
writeTimeout: TimeAmount = .minutes(1)
) throws -> AnyServer {
) throws -> some Server {
try self.validateContract(requiredBitmask: requiredBitmask)

return LGNS.Server(
Expand All @@ -63,8 +63,8 @@ public extension Service {
requiredBitmask: LGNP.Message.ControlBitmask = .defaultValues,
readTimeout: TimeAmount = .seconds(1),
writeTimeout: TimeAmount = .seconds(1)
) async throws -> AnyServer {
let server: AnyServer = try self.getServerLGNS(
) async throws -> some Server {
let server: some Server = try self.getServerLGNS(
at: target,
cryptor: cryptor,
eventLoopGroup: eventLoopGroup,
Expand Down
25 changes: 3 additions & 22 deletions Sources/LGNC/Service.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import LGNLog
import LGNP
import LGNS

/// A type-erased service
public protocol Service {
/// A storage for all keydictionaries of requests and responses of all contracts
static var keyDictionary: [String: Entita.Dict] { get }

/// A storage for storing `URI -> Contract` connection, used for routing
static var contractMap: [String: AnyContract.Type] { get }
static var contractMap: [String: any Contract.Type] { get }

/// Contains allowed service transports and respective ports
static var transports: [LGNCore.Transport: Int] { get }
Expand All @@ -35,24 +34,6 @@ public protocol Service {
URI: String,
dict: Entita.Dict
) async throws -> ContractExecutionResult

/// Starts a LGNS server at given target. Returns a future with a server, which must be waited for until claiming the server as operational.
static func startServerLGNS(
at target: LGNS.Server.BindTo?,
cryptor: LGNP.Cryptor,
eventLoopGroup: EventLoopGroup,
requiredBitmask: LGNP.Message.ControlBitmask,
readTimeout: TimeAmount,
writeTimeout: TimeAmount
) async throws -> AnyServer

/// Starts a HTTP server at given target. Returns a future with a server, which must be waited for until claiming the server as operational.
static func startServerHTTP(
at target: LGNS.Server.BindTo?,
eventLoopGroup: EventLoopGroup,
readTimeout: TimeAmount,
writeTimeout: TimeAmount
) async throws -> AnyServer
}

public extension Service {
Expand All @@ -62,13 +43,13 @@ public extension Service {

static var webSocketURI: String? { nil }

static var webSocketContracts: [AnyContract.Type] {
static var webSocketContracts: [any Contract.Type] {
self.contractMap
.map { $0.value }
.filter { $0.isWebSocketTransportAvailable }
}

static var webSocketOnlyContracts: [AnyContract.Type] {
static var webSocketOnlyContracts: [any Contract.Type] {
self.contractMap
.map { $0.value }
.filter { $0.transports == [.WebSocket] }
Expand Down
2 changes: 2 additions & 0 deletions Sources/LGNCore/BytesTrickery.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Foundation

// These are pretty much default for all packages and shouldn't clash with anything

public typealias Byte = UInt8
Expand Down
3 changes: 2 additions & 1 deletion Sources/LGNCore/RequestID.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
public extension LGNCore {
import Foundation

public extension LGNCore {
/// A random request ID.
///
/// Attention: this value is random, but not random enough to be used in sensitive cryptographic operations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import Foundation
import LGNLog
import NIO

public typealias LGNCoreServer = Server

/// A type-erased server type
public protocol AnyServer: AnyObject {
public protocol Server: AnyObject {
/// Indicates whether server is running (and serving requests) or not
var isRunning: Bool { get set }

Expand Down Expand Up @@ -33,7 +35,7 @@ public protocol AnyServer: AnyObject {
func waitForStop() throws
}

public extension AnyServer {
public extension Server {
fileprivate var name: String { "\(type(of: self))" }

@Sendable
Expand Down
1 change: 0 additions & 1 deletion Sources/LGNP/Cryptor.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Crypto
import Gzip
import LGNCore

public extension LGNP {
Expand Down
2 changes: 1 addition & 1 deletion Sources/LGNS/Server.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public extension LGNS {
static let DEFAULT_PORT = 1711

/// A LGNS server
class Server: AnyServer, @unchecked Sendable {
class Server: LGNCoreServer, @unchecked Sendable {
public typealias BindTo = LGNCore.Address

public static let defaultPort: Int = LGNS.DEFAULT_PORT
Expand Down
Loading

0 comments on commit 19b44af

Please sign in to comment.