Skip to content
This repository has been archived by the owner on Nov 19, 2023. It is now read-only.

Commit

Permalink
initial
Browse files Browse the repository at this point in the history
  • Loading branch information
tib committed Apr 28, 2020
0 parents commit c6dd394
Show file tree
Hide file tree
Showing 15 changed files with 386 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.DS_Store
.build
.swiftpm
Packages
*.xcodeproj
xcuserdata/
17 changes: 17 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004

Copyright (C) 2018-2019 Binary Birds

Authors:

Tibor Bodecs <mail.tib@gmail.com>

Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.

DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. You just DO WHAT THE FUCK YOU WANT TO.
23 changes: 23 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// swift-tools-version:5.2
import PackageDescription

let package = Package(
name: "liquid-kit",
platforms: [
.macOS(.v10_15)
],
products: [
.library(name: "LiquidKit", targets: ["LiquidKit"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"),
],
targets: [
.target(name: "LiquidKit", dependencies: [
.product(name: "NIO", package: "swift-nio"),
.product(name: "Logging", package: "swift-log"),
]),
.testTarget(name: "LiquidKitTests", dependencies: ["LiquidKit"]),
]
)
75 changes: 75 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# LiquidKit

Common interfaces for the Liquid file storage.


## Usage example

Add dependencies:

```swift
// swift-tools-version:5.2
import PackageDescription

let package = Package(
name: "myProject",
platforms: [
.macOS(.v10_15)
],
dependencies: [
// 💧 A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", from: "4.4.0"),
.package(url: "https://github.com/binarybirds/liquid.git", from: "0.0.1"),
.package(url: "https://github.com/binarybirds/liquid-local-driver.git", from: "0.0.1"),
],
targets: [
.target(name: "App", dependencies: [
.product(name: "Vapor", package: "vapor"),
.product(name: "Liquid", package: "liquid"),
.product(name: "LiquidLocalDriver", package: "liquid-local-driver"),
]),
]
)
```

Driver configuration

```swift
import Liquid
import LiquidLocalDriver

public func configure(_ app: Application) throws {

app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))

// using the local driver
app.fileStorages.use(.local(publicUrl: "http://localhost:8080/",
publicPath: app.directory.publicDirectory,
workDirectory: "assets"), as: .local)
}
```

File upload example:

```swift

func testUpload(req: Request) -> EventLoopFuture<String> {
let data: Data! = //...
let key = "path/to/my/file.txt"
return req.fs.upload(key: key, data: data)
// returns the full public url of the uploaded image
}

// resolve public url based on a key
// func resolve(key: String) -> String
req.fs.resolve(key: myImageKey)

// delete file based on a key
// func delete(key: String) -> EventLoopFuture<Void>
req.fs.delete(key: myImageKey)
```


## License

[WTFPL](LICENSE) - Do what the fuck you want to.
12 changes: 12 additions & 0 deletions Sources/LiquidKit/Exports.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// File.swift
//
//
// Created by Tibor Bodecs on 2020. 04. 28..
//

@_exported import Logging
@_exported import protocol NIO.EventLoop
@_exported import class NIO.EventLoopFuture
@_exported import struct NIO.EventLoopPromise
@_exported import protocol NIO.EventLoopGroup
22 changes: 22 additions & 0 deletions Sources/LiquidKit/FileStorage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// File.swift
//
//
// Created by Tibor Bodecs on 2020. 04. 28..
//

import Foundation
import NIO

public protocol FileStorage {
var context: FileStorageContext { get }

//returns a key as a full url
func resolve(key: String) -> String

// uploads the data under the given key
func upload(key: String, data: Data) -> EventLoopFuture<String>

// deletes the data under the given key
func delete(key: String) -> EventLoopFuture<Void>
}
13 changes: 13 additions & 0 deletions Sources/LiquidKit/FileStorageConfiguration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// File.swift
//
//
// Created by Tibor Bodecs on 2020. 04. 28..
//

import Foundation

public protocol FileStorageConfiguration {

func makeDriver(for: FileStorages) -> FileStorageDriver
}
17 changes: 17 additions & 0 deletions Sources/LiquidKit/FileStorageConfigurationFactory.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// File.swift
//
//
// Created by Tibor Bodecs on 2020. 04. 28..
//

import Foundation

public struct FileStorageConfigurationFactory {

public let make: () -> FileStorageConfiguration

public init(make: @escaping () -> FileStorageConfiguration) {
self.make = make
}
}
25 changes: 25 additions & 0 deletions Sources/LiquidKit/FileStorageContext.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// File.swift
//
//
// Created by Tibor Bodecs on 2020. 04. 28..
//

import NIO
import Logging
import Foundation

public struct FileStorageContext {
public let configuration: FileStorageConfiguration
public let logger: Logger
public let eventLoop: EventLoop

public init(configuration: FileStorageConfiguration,
logger: Logger,
eventLoop: EventLoop) {
self.configuration = configuration
self.logger = logger
self.eventLoop = eventLoop
}
}

13 changes: 13 additions & 0 deletions Sources/LiquidKit/FileStorageDriver.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// File.swift
//
//
// Created by Tibor Bodecs on 2020. 04. 28..
//

import Foundation

public protocol FileStorageDriver {
func makeStorage(with context: FileStorageContext) -> FileStorage
func shutdown()
}
15 changes: 15 additions & 0 deletions Sources/LiquidKit/FileStorageID.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// File.swift
//
//
// Created by Tibor Bodecs on 2020. 04. 28..
//

import Foundation

public struct FileStorageID: Hashable, Codable {
public let string: String
public init(string: String) {
self.string = string
}
}
117 changes: 117 additions & 0 deletions Sources/LiquidKit/FileStorages.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
//
// File.swift
//
//
// Created by Tibor Bodecs on 2020. 04. 28..
//

import Foundation
import NIO
import Logging
import Foundation
import class NIOConcurrencyHelpers.Lock
import class NIO.NIOThreadPool

public final class FileStorages {
// public let eventLoopGroup: EventLoopGroup
// public let threadPool: NIOThreadPool
public let fileio: NonBlockingFileIO

private var defaultID: FileStorageID?
private var configurations: [FileStorageID: FileStorageConfiguration]

// Currently running file storage drivers.
// Access to this variable must be synchronized.
private var drivers: [FileStorageID: FileStorageDriver]

// Synchronize access across threads.
private var lock: Lock

public init(fileio: NonBlockingFileIO) {
self.fileio = fileio
self.configurations = [:]
self.drivers = [:]
self.lock = .init()
}

public func use(_ factory: FileStorageConfigurationFactory, as id: FileStorageID, isDefault: Bool? = nil) {
self.use(factory.make(), as: id, isDefault: isDefault)
}

public func use(_ config: FileStorageConfiguration, as id: FileStorageID, isDefault: Bool? = nil) {
self.lock.lock()
defer { self.lock.unlock() }
self.configurations[id] = config
if isDefault == true || (self.defaultID == nil && isDefault != false) {
self.defaultID = id
}
}

public func `default`(to id: FileStorageID) {
self.lock.lock()
defer { self.lock.unlock() }
self.defaultID = id
}

public func configuration(for id: FileStorageID? = nil) -> FileStorageConfiguration? {
self.lock.lock()
defer { self.lock.unlock() }
return self.configurations[id ?? self._requireDefaultID()]
}

public func fileStorage(_ id: FileStorageID? = nil, logger: Logger, on eventLoop: EventLoop) -> FileStorage? {
self.lock.lock()
defer { self.lock.unlock() }
let id = id ?? self._requireDefaultID()
var logger = logger
logger[metadataKey: "file-storage-id"] = .string(id.string)
let configuration = self._requireConfiguration(for: id)
let context = FileStorageContext(
configuration: configuration,
logger: logger,
eventLoop: eventLoop
)
let driver: FileStorageDriver
if let existing = self.drivers[id] {
driver = existing
} else {
let new = configuration.makeDriver(for: self)
self.drivers[id] = new
driver = new
}
return driver.makeStorage(with: context)
}

public func reinitialize(_ id: FileStorageID? = nil) {
self.lock.lock()
defer { self.lock.unlock() }
let id = id ?? self._requireDefaultID()
if let driver = self.drivers[id] {
self.drivers[id] = nil
driver.shutdown()
}
}

public func shutdown() {
self.lock.lock()
defer { self.lock.unlock() }
for driver in self.drivers.values {
driver.shutdown()
}
self.drivers = [:]
}

private func _requireConfiguration(for id: FileStorageID) -> FileStorageConfiguration {
guard let configuration = self.configurations[id] else {
fatalError("No file storage configuration registered for \(id).")
}
return configuration
}

private func _requireDefaultID() -> FileStorageID {
guard let id = self.defaultID else {
fatalError("No default file storage configured.")
}
return id
}
}
7 changes: 7 additions & 0 deletions Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import XCTest

import LiquidKitTests

var tests = [XCTestCaseEntry]()
tests += LiquidKitTests.allTests()
XCTMain(tests)
15 changes: 15 additions & 0 deletions Tests/LiquidKitTests/LiquidKitTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import XCTest
@testable import LiquidKit

final class LiquidKitTests: XCTestCase {
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssertEqual(LiquidKit().text, "Hello, World!")
}

static var allTests = [
("testExample", testExample),
]
}
Loading

0 comments on commit c6dd394

Please sign in to comment.