Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
dileping committed Feb 26, 2016
2 parents 12f3fd9 + 560a244 commit 364e3d6
Show file tree
Hide file tree
Showing 45 changed files with 1,325 additions and 325 deletions.
5 changes: 5 additions & 0 deletions .gitignore
@@ -1,6 +1,11 @@
# Xcode
*.xcworkspace
xcuserdata

# Carthage
Cartfile.resolved
Carthage

# SPM
.build
Packages
102 changes: 69 additions & 33 deletions .travis.yml
@@ -1,36 +1,72 @@
language: objective-c
osx_image: xcode7.2
env:
global:
- FRAMEWORK_NAME=Express
before_install:
- brew update
- brew unlink carthage
- brew install carthage
- brew link carthage
- brew tap crossroadlabs/tap
- brew install libevhtp --without-oniguruma --with-shared
before_script:
# bootstrap the dependencies for the project
# you can remove if you don't have dependencies
- carthage bootstrap --platform osx
before_deploy:
- carthage build --no-skip-current
- carthage archive $FRAMEWORK_NAME
# - pod trunk push PathToRegex.podspec
script:
- xcodebuild build -project $FRAMEWORK_NAME.xcodeproj -scheme $FRAMEWORK_NAME
#- xcodebuild test -project Regex.xcodeproj -scheme Regex-iOS -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6'
#- xcodebuild test -project Regex.xcodeproj -scheme Regex-tvOS -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV 1080p'
#- xcodebuild build -project Regex.xcodeproj -scheme Regex-watchOS -sdk watchsimulator -destination 'platform=watchOS Simulator,name=Apple Watch - 42mm'
global:
- MODULE_NAME=Express
matrix:
include:
- script:
- xcodebuild build -project $MODULE_NAME.xcodeproj -scheme $MODULE_NAME
os: osx
osx_image: xcode7.2
language: objective-c
before_install:
- brew update
- brew unlink carthage
- brew install carthage
- brew link carthage
- brew tap crossroadlabs/tap
- brew install libevhtp --without-oniguruma --with-shared
before_script:
# bootstrap the dependencies for the project
# you can remove if you don't have dependencies
- carthage bootstrap --platform osx
before_deploy:
- carthage build --no-skip-current
- carthage archive $MODULE_NAME
deploy:
provider: releases
api_key:
secure: NxWvEe4nqcI99oKbtcFtmpz3AVkQiC+4kFu4OcCusAoKimMxx3WJ4+B6anDLG5dj/5rhsl4rQdKr/WIneHodyPrIFQPsRLUV2KFxgd+vbKrXLRRw+sZb//r0j89E7tCEUPdModIKWN4OCR7UWHvZ5syVQFfsP4MH1r+OJcBiewVVVPhgXzvndkxVlgXonyrJ++NAW/g+jO+CYNU9Y3KkyK7BaPMw6/oSC2Ly3A3zU1El++MFz+ew6YDGxiEiw7y20q7/qTT4pdl2HWem1P04UwPyJ2fUw/nD0C+fvX6tnFYX0s9p9VPSnrWXkhSHKT9IGlr8sveRPuQIaJcXcbkMHF8rnCmMpJJ63+YeXV88krW0q2ZyVpSodh/NaJ76PqbXij9WBSZ8AmNJsBlBsjhAgPCfZZkJ3vjrSSH2XP4k0ICLI8sxYmELXzR0MU1LaexE/4KKMDUcl4zuHWQBTJTMvtDyl+AJk+GdPBSGEpCQvHjXAwuW9OAz/sqZrLQy8eQJmji8DVhMJYlCK+krBQFZIekA6Wun5VTmATrtcwd6qwXyMOYeoblh3308zhzgyjBQwfJVpWxLLqB+dyQNLEOYhMcCcTwWNMvz7RYbEMcplkIu5azuUL400pPk2g2wp6U522vsAmH7bra3+VyA0qYG0ckLiwBaBKVCxD7EzkAy5CA=
file: $MODULE_NAME.framework.zip
skip_cleanup: true
on:
repo: crossroadlabs/Express
tags: true
- script:
- ./build
sudo: required
dist: trusty
language: generic
before_install:
# install original swift distribution
- wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
- cd ..
- export SWIFT_VERSION=swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a
- wget https://swift.org/builds/development/ubuntu1404/$SWIFT_VERSION/$SWIFT_VERSION-ubuntu14.04.tar.gz
- tar xzf $SWIFT_VERSION-ubuntu14.04.tar.gz
- export PATH="${PWD}/${SWIFT_VERSION}-ubuntu14.04/usr/bin:${PATH}"
# install latest package manager with `swift-test`
- git clone https://github.com/apple/swift-package-manager
- cd swift-package-manager
- Utilities/bootstrap
- export SWIFT_BUILD_PATH=`pwd`
- export PATH=$SWIFT_BUILD_PATH/.build/debug:$PATH
- cd ..
# express dependencies
# - sudo apt-get install libevhtp-dev libevent-dev libssl-dev //libevhtp-dev is not available on trusty
- sudo apt-get update
- sudo apt-get install libevent-dev libssl-dev
- git clone https://github.com/ellzey/libevhtp.git
- cd libevhtp
- git checkout tags/1.2.10
- cmake -DEVHTP_DISABLE_REGEX:STRING=ON -DEVHTP_BUILD_SHARED:STRING=ON -DCMAKE_INSTALL_PREFIX:STRING=/usr
- make
- sudo make install
- cd ..
# get back home
- cd $MODULE_NAME
# get crossroad build script
- wget https://raw.githubusercontent.com/crossroadlabs/utils/master/build
- chmod +x build
notifications:
email: false
deploy:
provider: releases
api_key:
secure: NxWvEe4nqcI99oKbtcFtmpz3AVkQiC+4kFu4OcCusAoKimMxx3WJ4+B6anDLG5dj/5rhsl4rQdKr/WIneHodyPrIFQPsRLUV2KFxgd+vbKrXLRRw+sZb//r0j89E7tCEUPdModIKWN4OCR7UWHvZ5syVQFfsP4MH1r+OJcBiewVVVPhgXzvndkxVlgXonyrJ++NAW/g+jO+CYNU9Y3KkyK7BaPMw6/oSC2Ly3A3zU1El++MFz+ew6YDGxiEiw7y20q7/qTT4pdl2HWem1P04UwPyJ2fUw/nD0C+fvX6tnFYX0s9p9VPSnrWXkhSHKT9IGlr8sveRPuQIaJcXcbkMHF8rnCmMpJJ63+YeXV88krW0q2ZyVpSodh/NaJ76PqbXij9WBSZ8AmNJsBlBsjhAgPCfZZkJ3vjrSSH2XP4k0ICLI8sxYmELXzR0MU1LaexE/4KKMDUcl4zuHWQBTJTMvtDyl+AJk+GdPBSGEpCQvHjXAwuW9OAz/sqZrLQy8eQJmji8DVhMJYlCK+krBQFZIekA6Wun5VTmATrtcwd6qwXyMOYeoblh3308zhzgyjBQwfJVpWxLLqB+dyQNLEOYhMcCcTwWNMvz7RYbEMcplkIu5azuUL400pPk2g2wp6U522vsAmH7bra3+VyA0qYG0ckLiwBaBKVCxD7EzkAy5CA=
file: $FRAMEWORK_NAME.framework.zip
skip_cleanup: true
on:
repo: crossroadlabs/$FRAMEWORK_NAME
tags: true

11 changes: 6 additions & 5 deletions Cartfile
@@ -1,6 +1,7 @@
github "crossroadlabs/BrightFutures" "master"
github "SwiftyJSON/SwiftyJSON"
github "crossroadlabs/BrightFutures" ~> 0.4
github "crossroadlabs/TidyJSON" ~> 1.1
github "groue/GRMustache.swift" "Swift2.1"
github "crossroadlabs/Regex" ~> 0.4
github "crossroadlabs/PathToRegex" ~> 0.1
github "crossroadlabs/CEVHTP" ~> 0.1.0
github "crossroadlabs/Regex" ~> 0.5
github "crossroadlabs/PathToRegex" ~> 0.2
github "crossroadlabs/CEVHTP" ~> 0.1
github "crossroadlabs/Stencil" ~> 0.5
172 changes: 65 additions & 107 deletions Demo/main.swift
Expand Up @@ -17,38 +17,43 @@ let app = express()

app.views.register(JsonView())
app.views.register(MustacheViewEngine())
app.views.register(StencilViewEngine())

enum TestError {
case Test
case Test2

func items() -> Dictionary<String, String> {
switch self {
case .Test: return ["blood": "red"]
case .Test2: return ["sickness": "purple"]
}
}
app.get("/echo") { request in
return Action.ok(request.query["call"]?.first)
}

extension TestError : ErrorType {
enum NastyError : ErrorType {
case Recoverable
case Fatal(reason:String)
}

func test() throws -> Action<AnyContent> {
throw TestError.Test2
app.get("/error/:fatal?") { request in
guard let fatal = request.params["fatal"] else {
throw NastyError.Recoverable
}

throw NastyError.Fatal(reason: fatal)
}

app.errorHandler.register { e in
guard let e = e as? TestError else {
return nil
app.errorHandler.register { (e:NastyError) in
switch e {
case .Recoverable:
return Action<AnyContent>.redirect("/")
case .Fatal(let reason):
let content = AnyContent(str: "Unrecoverable nasty error happened. Reason: " + reason)
return Action<AnyContent>.response(.InternalServerError, content: content)
}

let items = e.items()

let viewItems = items.map { (k, v) in
["name": k, "color": v]
}

/// Custom page not found error handler
app.errorHandler.register { (e:ExpressError) in
switch e {
case .PageNotFound(let path):
return Action<AnyContent>.render("404", context: ["path": path], status: .NotFound)
default:
return nil
}

return Action<AnyContent>.render("test", context: ["test": "error", "items": viewItems])
}

/// StaticAction is just a predefined configurable handler for serving static files.
Expand Down Expand Up @@ -87,21 +92,17 @@ app.post("/api/user") { request in
return Action.render(JsonView.name, context: response)
}

app.get("/myecho") { request in
return Action.ok(request.query["message"]?.first)
}

//:param - this is how you define a part of URL you want to receive through request object
app.get("/myecho/:param") { request in
app.get("/echo/:param") { request in
//here you get the param from request: request.params["param"]
return Action.ok(request.params["param"])
}

func factorial(n: Int) -> Int {
func factorial(n: Double) -> Double {
return n == 0 ? 1 : n * factorial(n - 1)
}

func calcFactorial(num:Int) -> Future<Int, AnyError> {
func calcFactorial(num:Double) -> Future<Double, AnyError> {
return future {
return factorial(num)
}
Expand All @@ -111,7 +112,7 @@ func calcFactorial(num:Int) -> Future<Int, AnyError> {
// hopefully inference in swift will get better eventually and just "request in" will be enough
app.get("/factorial/:num(\\d+)") { request -> Future<Action<AnyContent>, AnyError> in
// get the number from the url
let num = request.params["num"].flatMap{Int($0)}.getOrElse(0)
let num = request.params["num"].flatMap{Double($0)}.getOrElse(0)

// get the factorial Future. Returns immediately - non-blocking
let factorial = calcFactorial(num)
Expand All @@ -125,13 +126,7 @@ app.get("/factorial/:num(\\d+)") { request -> Future<Action<AnyContent>, AnyErro
return future
}

app.get("/test") { req in
return future {
return try test()
}
}

app.get("/test.html") { request in
func testItems(request:Request<AnyContent>) throws -> [String: Any] {
let newItems = request.query.map { (k, v) in
(k, v.first!)
}
Expand All @@ -141,90 +136,53 @@ app.get("/test.html") { request in
["name": k, "color": v]
}

if ((request.query["throw"]?.first) != nil) {
throw TestError.Test
if let reason = request.query["throw"]?.first {
throw NastyError.Fatal(reason: reason)
}

return Action.render("test", context: ["test": "ok", "items": viewItems])
}

app.get("/echo") { request in
return Action.chain()
return ["test": "ok", "items": viewItems]
}

app.get("/myecho") { request in
return Action.ok(AnyContent(str: request.query["message"]?.first))
}

app.get("/hello") { request in
return Action.ok(AnyContent(str: "<h1>Hello Express!!!</h1>", contentType: "text/html"))
app.get("/render.html") { request in
let items = try testItems(request)
return Action.render("test", context: items)
}

//TODO: make a list of pages
app.get("/") { request in
for me in request.body?.asJSON().map({$0["test"]}) {
print(me)
}
return Action.ok(AnyContent(str:"{\"response\": \"hey hey\"}", contentType: "application/json"))
}

func echoData(request:Request<AnyContent>) -> Dictionary<String, String> {
let call = request.body?.asJSON().map({$0["say"]})?.string
let response = call.getOrElse("I don't hear you!")
return ["said": response]
}

func echo(request:Request<AnyContent>) -> Action<AnyContent> {
let data = echoData(request)
let tuple = data.first!
let str = "{\"" + tuple.0 + "\": \"" + tuple.1 + "\"}"
let examples:[Any] = [
["title": "Hello Express", "link": "/hello"],
["title": "Echo", "link": "/echo?call=hello"],
["title": "Echo with param", "link": "/echo/hello"],
["title": "Error recoverable (will redirect back)", "link": "/error"],
["title": "Error fatal", "link": "/error/thebigbanghappened"],
["title": "Custom 404", "link": "/thisfiledoesnotexist"],
["title": "Hello [username]. You can put your name instead", "link": "/hello/username.html"],
///api/user - implement JSON post form
["title": "Asynchronous factorial", "link": "/factorial/100"],
["title": "Render", "link": "/render.html?sun=yellow&clouds=lightgray"],
["title": "Redirect", "link": "/test/redirect"],
["title": "Merged query (form url encoded and query string)", "link": "/merged/query?some=param&another=param2"],
]

return Action<AnyContent>.ok(AnyContent(str:str, contentType: "application/json"))
}

func echoRender(request:Request<AnyContent>) -> Action<AnyContent> {
var data = echoData(request)
data["hey"] = "Hello from render"
return Action.render(JsonView.name, context: data)
}

app.post("/echo/inline") { request in
let call = request.body?.asJSON().map({$0["say"]})?.string
let response = call.getOrElse("I don't hear you!")
let context:[String: Any] = ["examples": examples]

return Action.ok(AnyContent(str:"{\"said\": \"" + response + "\"}", contentType: "application/json"))
}

app.get("/echo") { request in
return echo(request)
}

app.get("/echo/render", handler: echoRender)
app.post("/echo/render", handler: echoRender)

app.post("/echo") { request in
return echo(request)
}

app.post("/echo2") { request in
return Action.ok(AnyContent(str: request.body?.asText().map {"Text echo: " + $0},
contentType: request.contentType))
}

app.post("/echo3") { request in
return Action.ok(AnyContent(data: request.body?.asRaw(),
contentType: request.contentType))
return Action.render("index", context: context)
}

app.all("/async/echo") { request in
app.get("/test/redirect") { request in
return future {
return echo(request)
let to = request.query["to"].flatMap{$0.first}.getOrElse("../render.html")
return Action.redirect(to)
}
}

app.listen(9999).onSuccess {
print("Successfully launched server")
app.all("/merged/query") { request in
Action.render(JsonView.name, context: request.mergedQuery())
}

app.run()
app.listen(9999).onSuccess { server in
print("Express was successfully launched on port", server.port)
}

//TODO: proper error handling for sync requests
app.run()
7 changes: 7 additions & 0 deletions Demo/views/404.stencil
@@ -0,0 +1,7 @@
<html>
<body>
<p align="center"><a href="#swift-express"><img src ="/logo.png" height=256/></a></p>
<h1 align="center">404: Page not found</h1>
<h2>{{path}}</h2>
</body>
</html>
1 change: 0 additions & 1 deletion Demo/views/colored.mustache

This file was deleted.

1 change: 1 addition & 0 deletions Demo/views/colored.stencil
@@ -0,0 +1 @@
<li type="disk">Item: <span style="color:{{item.color}}">{{item.name}}</span></li>
5 changes: 0 additions & 5 deletions Demo/views/hello.mustache

This file was deleted.

5 changes: 5 additions & 0 deletions Demo/views/hello.stencil
@@ -0,0 +1,5 @@
<html>
<body>
<h1>Hello from Stencil: {{user}}</h1>
</body>
</html>

0 comments on commit 364e3d6

Please sign in to comment.