All Projects → envoy → Embassy

envoy / Embassy

Licence: mit
Super lightweight async HTTP server library in pure Swift runs in iOS / MacOS / Linux

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Embassy

Proxy.py
⚡⚡⚡Fast, Lightweight, Pluggable, TLS interception capable proxy server focused on Network monitoring, controls & Application development, testing, debugging
Stars: ✭ 1,291 (+193.41%)
Mutual labels:  lightweight, webserver
Katwebx
An extremely fast static web server and reverse proxy for the modern web.
Stars: ✭ 39 (-91.14%)
Mutual labels:  lightweight, webserver
Qtwebserver
Qt based web application server
Stars: ✭ 56 (-87.27%)
Mutual labels:  lightweight, webserver
Lightcomm4j
Yet another lightweight asynchronous network library for java
Stars: ✭ 25 (-94.32%)
Mutual labels:  asynchronous, lightweight
Esa Restlight
ESA Restlight is a lightweight and rest-oriented web framework.
Stars: ✭ 67 (-84.77%)
Mutual labels:  asynchronous, lightweight
khudro
Khudro is a very light weight web-server built with C.
Stars: ✭ 19 (-95.68%)
Mutual labels:  lightweight, webserver
Ambassador
Super lightweight web framework in Swift based on SWSGI
Stars: ✭ 152 (-65.45%)
Mutual labels:  asynchronous, webserver
picamera-motion
Raspberry Pi python PiCamera Lightweight Motion Detection. Includes easy curl script install/upgrade, whiptail admin menu system, single file web server and Rclone for uploading to a variety of web storage services.
Stars: ✭ 80 (-81.82%)
Mutual labels:  lightweight, webserver
Espnetv2
A light-weight, power efficient, and general purpose convolutional neural network
Stars: ✭ 377 (-14.32%)
Mutual labels:  lightweight
Bocadillo
(UNMAINTAINED) Fast, scalable and real-time capable web APIs for everyone
Stars: ✭ 401 (-8.86%)
Mutual labels:  asynchronous
Httplab
The interactive web server
Stars: ✭ 3,752 (+752.73%)
Mutual labels:  webserver
Transmittable Thread Local
📌 TransmittableThreadLocal (TTL), the missing Java™ std lib(simple & 0-dependency) for framework/middleware, provide an enhanced InheritableThreadLocal that transmits values between threads even using thread pooling components.
Stars: ✭ 4,678 (+963.18%)
Mutual labels:  asynchronous
Binserve
A blazingly fast static web server with routing, templating, and security in a single binary you can set up with zero code. ⚡️🦀
Stars: ✭ 401 (-8.86%)
Mutual labels:  webserver
Momoko
Wraps (asynchronous) Psycopg2 for Tornado.
Stars: ✭ 374 (-15%)
Mutual labels:  asynchronous
Nier Visualizer
A lightweight and efficient Android visual library.
Stars: ✭ 421 (-4.32%)
Mutual labels:  lightweight
Nodemcu Httpserver
A (very) simple web server written in Lua for the ESP8266 firmware NodeMCU.
Stars: ✭ 369 (-16.14%)
Mutual labels:  webserver
Oatpp
🌱Light and powerful C++ web framework for highly scalable and resource-efficient web application. It's zero-dependency and easy-portable.
Stars: ✭ 4,750 (+979.55%)
Mutual labels:  webserver
Quill
Asynchronous Low Latency C++ Logging Library
Stars: ✭ 422 (-4.09%)
Mutual labels:  asynchronous
Microwebsrv
A micro HTTP Web server that supports WebSockets, html/python language templating and routing handlers, for MicroPython (used on Pycom modules & ESP32)
Stars: ✭ 420 (-4.55%)
Mutual labels:  webserver
Lettuce Core
Advanced Java Redis client for thread-safe sync, async, and reactive usage. Supports Cluster, Sentinel, Pipelining, and codecs.
Stars: ✭ 4,319 (+881.59%)
Mutual labels:  asynchronous

Embassy

Build Status Carthage compatible SwiftPM compatible CocoaPods Swift Version Plaform GitHub license

Super lightweight async HTTP server in pure Swift.

Please read: Embedded web server for iOS UI testing.

See also: Our lightweight web framework Ambassador based on Embassy

Features

  • Swift 4 & 5
  • iOS / tvOS / MacOS / Linux
  • Super lightweight, only 1.5 K of lines
  • Zero third-party dependency
  • Async event loop based HTTP server, makes long-polling, delay and bandwidth throttling all possible
  • HTTP Application based on SWSGI, super flexible
  • IPV6 ready, also supports IPV4 (dual stack)
  • Automatic testing covered

Example

Here's a simple example shows how Embassy works.

let loop = try! SelectorEventLoop(selector: try! KqueueSelector())
let server = DefaultHTTPServer(eventLoop: loop, port: 8080) {
    (
        environ: [String: Any],
        startResponse: ((String, [(String, String)]) -> Void),
        sendBody: ((Data) -> Void)
    ) in
    // Start HTTP response
    startResponse("200 OK", [])
    let pathInfo = environ["PATH_INFO"]! as! String
    sendBody(Data("the path you're visiting is \(pathInfo.debugDescription)".utf8))
    // send EOF
    sendBody(Data())
}

// Start HTTP server to listen on the port
try! server.start()

// Run event loop
loop.runForever()

Then you can visit http://[::1]:8080/foo-bar in the browser and see

the path you're visiting is "/foo-bar"

Async Event Loop

To use the async event loop, you can get it via key embassy.event_loop in environ dictionary and cast it to EventLoop. For example, you can create an SWSGI app which delays sendBody call like this

let app = { (
    environ: [String: Any],
    startResponse: ((String, [(String, String)]) -> Void),
    sendBody: @escaping ((Data) -> Void)
) in
    startResponse("200 OK", [])

    let loop = environ["embassy.event_loop"] as! EventLoop

    loop.call(withDelay: 1) {
        sendBody(Data("hello ".utf8))
    }
    loop.call(withDelay: 2) {
        sendBody(Data("baby ".utf8))
    }
    loop.call(withDelay: 3) {
        sendBody(Data("fin".utf8))
        sendBody(Data())
    }
}

Please notice that functions passed into SWSGI should be only called within the same thread for running the EventLoop, they are all not threadsafe, therefore, you should not use GCD for delaying any call. Instead, there are some methods from EventLoop you can use, and they are all threadsafe

call(callback: (Void) -> Void)

Call given callback as soon as possible in the event loop

call(withDelay: TimeInterval, callback: (Void) -> Void)

Schedule given callback to withDelay seconds then call it in the event loop.

call(atTime: Date, callback: (Void) -> Void)

Schedule given callback to be called at atTime in the event loop. If the given time is in the past or zero, this methods works exactly like call with only callback parameter.

What's SWSGI (Swift Web Server Gateway Interface)?

SWSGI is a hat tip to Python's WSGI (Web Server Gateway Interface). It's a gateway interface enables web applications to talk to HTTP clients without knowing HTTP server implementation details.

It's defined as

public typealias SWSGI = (
    [String: Any],
    @escaping ((String, [(String, String)]) -> Void),
    @escaping ((Data) -> Void)
) -> Void

environ

It's a dictionary contains all necessary information about the request. It basically follows WSGI standard, except wsgi.* keys will be swsgi.* instead. For example:

[
  "SERVER_NAME": "[::1]",
  "SERVER_PROTOCOL" : "HTTP/1.1",
  "SERVER_PORT" : "53479",
  "REQUEST_METHOD": "GET",
  "SCRIPT_NAME" : "",
  "PATH_INFO" : "/",
  "HTTP_HOST": "[::1]:8889",
  "HTTP_USER_AGENT" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36",
  "HTTP_ACCEPT_LANGUAGE" : "en-US,en;q=0.8,zh-TW;q=0.6,zh;q=0.4,zh-CN;q=0.2",
  "HTTP_CONNECTION" : "keep-alive",
  "HTTP_ACCEPT" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
  "HTTP_ACCEPT_ENCODING" : "gzip, deflate, sdch",
  "swsgi.version" : "0.1",
  "swsgi.input" : (Function),
  "swsgi.error" : "",
  "swsgi.multiprocess" : false,
  "swsgi.multithread" : false,
  "swsgi.url_scheme" : "http",
  "swsgi.run_once" : false
]

To read request from body, you can use swsgi.input, for example

let input = environ["swsgi.input"] as! SWSGIInput
input { data in
    // handle the body data here
}

An empty Data will be passed into the input data handler when EOF reached. Also please notice that, request body won't be read if swsgi.input is not set or set to nil. You can use swsgi.input as bandwidth control, set it to nil when you don't want to receive any data from client.

Some extra Embassy server specific keys are

  • embassy.connection - HTTPConnection object for the request
  • embassy.event_loop - EventLoop object
  • embassy.version - Version of embassy as a String, e.g. 3.0.0

startResponse

Function for starting to send HTTP response header to client, the first argument is status code with message, e.g. "200 OK". The second argument is headers, as a list of key value tuple.

To response HTTP header, you can do

startResponse("200 OK", [("Set-Cookie", "foo=bar")])

startResponse can only be called once per request, extra call will be simply ignored.

sendBody

Function for sending body data to client. You need to call startResponse first in order to call sendBody. If you don't call startResponse first, all calls to sendBody will be ignored. To send data, here you can do

sendBody(Data("hello".utf8))

To end the response data stream simply call sendBody with an empty Data.

sendBody(Data())

Install

CocoaPods

To install with CocoaPod, add Embassy to your Podfile:

pod 'Embassy', '~> 4.1'

Carthage

To install with Carthage, add Embassy to your Cartfile:

github "envoy/Embassy" ~> 4.1

Package Manager

Add it this Embassy repo in Package.swift, like this

import PackageDescription

let package = Package(
    name: "EmbassyExample",
    dependencies: [
        .package(url: "https://github.com/envoy/Embassy.git",
                 from: "4.1.1"),
    ]
)

You can read this example project here.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].