Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/skylab-inc/Lightning

A Swift Multiplatform Single-threaded Non-blocking Web and Networking Framework
https://github.com/skylab-inc/Lightning

asynchronous asynchronous-events edge frp functional-reactive-programming libdispatch lightning nodejs non-blocking non-blocking-sockets nonblocking reactivecocoa single-thread swift swift-package-manager swift4 tcp thread-safe

Last synced: about 2 months ago
JSON representation

A Swift Multiplatform Single-threaded Non-blocking Web and Networking Framework

Lists

README

        


Edge

Serverside non-blocking IO in Swift

Ask questions in our Slack channel!

# Lightning
##### (formerly Edge)

![Swift](http://img.shields.io/badge/swift-4.0.2-brightgreen.svg)
[![Build Status](https://travis-ci.org/skylab-inc/Lightning.svg?branch=master)](https://travis-ci.org/skylab-inc/Lightning)
[![codecov](https://codecov.io/gh/skylab-inc/Lightning/branch/master/graph/badge.svg)](https://codecov.io/gh/skylab-inc/Lightning)
[![Slack Status](https://slackin-on-edge.herokuapp.com/badge.svg)](https://slackin-on-edge.herokuapp.com)

#### Node
Lightning is an HTTP Server and TCP Client/Server framework written in Swift and inspired by [Node.js](https://nodejs.org). It runs on both OS X and Linux. Like Node.js, Lightning uses an **event-driven, non-blocking I/O model**. In the same way that Node.js uses [libuv](http://libuv.org) to implement this model, Lightning uses [libdispatch](https://github.com/apple/swift-corelibs-libdispatch).

This makes Lightning fast, efficient, and most crutially **single-threaded** by default. You simply do not need to worry about locks/mutexes/semaphores/etc if you have server-side state. Of course, Lightning applications can make use of libdispatch to easily offload heavy processing to a background thread if necessary.

#### Reactive Programming
Lightning's event API embraces Functional Reactive Programming by generalizing the familiar concept of promises. This API is called [StreamKit](https://github.com/skylab-inc/StreamKit).

> StreamKit's architecture is inspired by both [ReactiveCocoa](https://github.com/ReactiveCocoa/ReactiveCocoa) and [RxSwift](https://github.com/ReactiveX/RxSwift).

##### Why did we reimplement?
* Lightning should be easy to use out of the box.
* Lightning is optimized for maximum performance, which requires careful tuning of the internals.
* The modified API is meant to be more similar to the familiar concepts of Futures and Promises.
* We don't want to be opinionated about any one framework. We want it to be easy to integate Lightning with either ReactiveCocoa or RxSwift.

>FRP, greatly simplies management of asynchronous events. The general concept is that we can build a spout which pushes out asynchronous events as they happen. Then we hookup a pipeline of transformations that operate on events and pass the transformed values along. We can even do things like merge streams in interesting ways! Take a look at some of these [operations](http://rxmarbles.com) or watch [this talk](https://www.youtube.com/watch?v=XRYN2xt11Ek) about how FRP is used at Netflix.

# Installation

Lightning is available as a Swift 3/4 package. Simply add Lightning as a dependency to your Swift Package.

Swift 3
```Swift
import PackageDescription

let package = Package(
name: "MyProject",
dependencies: [
.Package(url: "https://github.com/skylab-inc/Lightning.git", majorVersion: 0, minor: 3)
]
)
```
Swift 4
```Swift
// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription

let package = Package(
name: "MyProject",
dependencies: [
.package(url: "https://github.com/skylab-inc/Lightning.git", from: "0.3.0"),
]
)
```

# Usage

### Routing
```swift
import Lightning
import Foundation

// Create an API router.
let api = Router()

// Add a GET "/users" endpoint.
api.get("/users") { request in
return Response(status: .ok)
}

// NOTE: Equivalent to `api.post("/auth/login")`
let auth = api.subrouter("/auth")
auth.post("/login") { request in
return Response(status: .ok)
}

// Middleware to log all requests
// NOTE: Middleware is a simple as a map function or closure!
let app = Router()
app.map { request in
print(request)
return request
}

// Mount the API router under "/v1.0".
app.add("/v1.0", api)

// NOTE: Warnings on all unhandled requests. No more hanging clients!
app.any { _ in
return Response(status: .notFound)
}

// Start the application.
app.start(host: "0.0.0.0", port: 3000)
```

### Raw HTTP
```swift
import Lightning
import Foundation

func handleRequest(request: Request) -> Response {
print(String(bytes: request.body, encoding: .utf8)!)
return try! Response(json: ["message": "Message received!"])
}

let server = HTTP.Server()
server.listen(host: "0.0.0.0", port: 3000).startWithNext { client in

let requestStream = client.read()
requestStream.map(handleRequest).onNext{ response in
client.write(response).start()
}

requestStream.onFailed { clientError in
print("Oh no, there was an error! \(clientError)")
}

requestStream.onCompleted {
print("Goodbye \(client)!")
}

requestStream.start()
}

RunLoop.runAll()
```

### TCP
```Swift

import Lightning
import Foundation

let server = try! TCP.Server()
try! server.bind(host: "0.0.0.0", port: 50000)

server.listen().startWithNext { connection in
let byteStream = connection.read()
let strings = byteStream.map { String(bytes: $0, encoding: .utf8)! }

strings.onNext { message in
print("Client \(connection) says \"\(message)\"!")
}

strings.onFailed { error in
print("Oh no, there was an error! \(error)")
}

strings.onCompleted {
print("Goodbye \(connection)!")
}

strings.start()
}

RunLoop.runAll()
```

### Lightning is not Node.js

Lightning is not meant to fulfill all of the roles of Node.js. Node.js is a JavaScript runtime, while Lightning is a TCP/Web server framework. The Swift compiler and package manager, combined with third-party Swift packages, make it unnecessary to build that functionality into Lightning.