|
1 | | -# swift-nio-redis |
2 | | -A high performance Redis protocol implementation for SwiftNIO |
| 1 | +# SwiftNIO Redis |
| 2 | + |
| 3 | +SwiftNIO Redis is a Swift package that contains a high performance |
| 4 | +[Redis protocol](https://redis.io/topics/protocol) |
| 5 | +implementation for |
| 6 | +[SwiftNIO](https://github.com/apple/swift-nio). |
| 7 | +This is a **standalone project** and has no other dependencies but |
| 8 | +[SwiftNIO](https://github.com/apple/swift-nio). |
| 9 | + |
| 10 | +Apart from the protocol implementation which can encode and decode |
| 11 | +[RESP](https://redis.io/topics/protocol) (REdis Serialization Protocol), |
| 12 | +we also provide a [Redis client module](Sources/Redis/README.md) |
| 13 | +build on top. |
| 14 | + |
| 15 | +What is Redis? |
| 16 | +[Redis](https://redis.io/) is a highly scalable in-memory data structure store, |
| 17 | +used as a database, cache and message broker. |
| 18 | +For example it can be used to implement a session store backing a web backend |
| 19 | +using its "expiring keys" feature, |
| 20 | +or it can be used as a relay to implement a chat server using its builtin |
| 21 | +[PubSub](https://redis.io/topics/pubsub) |
| 22 | +features. |
| 23 | + |
| 24 | +## Performance |
| 25 | + |
| 26 | +This implementation is focused on performance. |
| 27 | +It tries to reuse NIO `ByteBuffer`s as much as possible to avoid copies. |
| 28 | + |
| 29 | +The parser is based on a state machine, not on a buffering |
| 30 | +`ByteToMessageDecoder`/Encoder. |
| 31 | +That doesn't make it nice, but efficient ;-) |
| 32 | + |
| 33 | +## Importing the module using Swift Package Manager |
| 34 | + |
| 35 | +An example `Package.swift `importing the necessary modules: |
| 36 | + |
| 37 | +```swift |
| 38 | +// swift-tools-version:4.0 |
| 39 | + |
| 40 | +import PackageDescription |
| 41 | + |
| 42 | +let package = Package( |
| 43 | + name: "RedisTests", |
| 44 | + dependencies: [ |
| 45 | + .package(url: "https://github.com/NozeIO/swift-nio-redis.git", |
| 46 | + from: "0.8.0") |
| 47 | + ], |
| 48 | + targets: [ |
| 49 | + .target(name: "MyProtocolTool", |
| 50 | + dependencies: [ "NIORedis" ]), |
| 51 | + .target(name: "MyClientTool", |
| 52 | + dependencies: [ "Redis" ]) |
| 53 | + ] |
| 54 | +) |
| 55 | +``` |
| 56 | + |
| 57 | + |
| 58 | +## Using the SwiftNIO Redis protocol handler |
| 59 | + |
| 60 | +The RESP protocol handler just implemented as a regular |
| 61 | +`ChannelHandler`, similar to `NIOHTTP1`. |
| 62 | +It takes incoming `ByteBuffer` data, parses that, and emits `RESPValue` |
| 63 | +items. |
| 64 | +Same the other way around, the user writes `RESPValue` (or `RESPEncodable`) |
| 65 | +objects, and the handler renders such into `ByteBuffer`s. |
| 66 | + |
| 67 | +The [NIORedis module](Sources/NIORedis/README.md) has a litte more |
| 68 | +information. |
| 69 | + |
| 70 | +To add the RESP handler to a NIO Channel pipeline, the `configureRedisPipeline` |
| 71 | +method is called, e.g.: |
| 72 | + |
| 73 | +```swift |
| 74 | +bootstrap.channelInitializer { channel in |
| 75 | + channel.pipeline |
| 76 | + .configureRedisPipeline() |
| 77 | + .then { ... } |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | + |
| 82 | +## Using the Redis client module |
| 83 | + |
| 84 | +The `Redis` module is modeled after the Node.js |
| 85 | +[node_redis](https://github.com/NodeRedis/node_redis) |
| 86 | +module, |
| 87 | +but it also supports NIO like Promise/Future based methods in addition |
| 88 | +to the Node.js `(err,result)` style callbacks. Choose your poison. |
| 89 | + |
| 90 | +### Simple KVS use example: |
| 91 | + |
| 92 | +```swift |
| 93 | +import Redis |
| 94 | + |
| 95 | +let client = Redis.createClient() |
| 96 | + |
| 97 | +client.set ("counter", 0, expire: 2) |
| 98 | +client.incr("counter", by: 10) |
| 99 | +client.get ("counter") { err, value in |
| 100 | + print("Reply:", value) |
| 101 | +} |
| 102 | +client.keys("*") { err, reply in |
| 103 | + guard let keys = reply else { return print("got no keys!") } |
| 104 | + print("all keys in store:", keys.joined(separator: ",")) |
| 105 | +} |
| 106 | +``` |
| 107 | + |
| 108 | +Using NIO Promises: |
| 109 | + |
| 110 | +```swift |
| 111 | +client |
| 112 | + .set ("counter", 0, expire: 2) |
| 113 | + .then { |
| 114 | + client.incr("counter", by: 10) |
| 115 | + } |
| 116 | + .then { |
| 117 | + client.get("counter") |
| 118 | + } |
| 119 | + .map { |
| 120 | + print("counter is:", $0) |
| 121 | + } |
| 122 | +``` |
| 123 | + |
| 124 | + |
| 125 | +## Status |
| 126 | + |
| 127 | +The |
| 128 | +[protocol implementation](Sources/NIORedis/) |
| 129 | +is considered complete. There are a few open ends |
| 130 | +in the `telnet` variant, yet the regular binary protocol is considered done. |
| 131 | + |
| 132 | +The |
| 133 | +[Redis client module](Sources/Redis/) |
| 134 | +has a few more open ends, but seems to work fine. |
| 135 | + |
| 136 | + |
| 137 | +### Who |
| 138 | + |
| 139 | +Brought to you by |
| 140 | +[ZeeZide](http://zeezide.de). |
| 141 | +We like |
| 142 | +[feedback](https://twitter.com/ar_institute), |
| 143 | +GitHub stars, |
| 144 | +cool [contract work](http://zeezide.com/en/services/services.html), |
| 145 | +presumably any form of praise you can think of. |
0 commit comments