Skip to content

Commit

Permalink
Merge pull request #1 from aus-der-Technik/release/2.2.0
Browse files Browse the repository at this point in the history
Release/2.2.0
  • Loading branch information
KrisSimon committed Oct 22, 2021
2 parents e29c271 + dc7dce2 commit 85d0bf4
Show file tree
Hide file tree
Showing 30 changed files with 243 additions and 206 deletions.
23 changes: 3 additions & 20 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,22 +1,5 @@
# Additional licence information, added 2021 by aus der Technik:
BSD-0 License, 2021 - aus der Technik https://www.ausdertechnik.de

Do whatever you want with it, as long as it is in good intention.
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.


# Original Copyright 2018 by Ray Krow

Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.[19]
93 changes: 73 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
# SwiftyNats
A maintained swift client for interacting with a [nats](http://nats.io) server working with NIO2.
A maintained swift client for interacting with a [nats](http://nats.io) server based on NIO2.

![SwiftyNats Logo](./Resources/Logo@256.png)

Tested with Swift 5.4 on [![macos](https://github.com/aus-der-Technik/swifty-nats/actions/workflows/macos.yml/badge.svg?branch=main)](https://github.com/aus-der-Technik/swifty-nats/actions/workflows/macos.yml) and [![Linux](https://github.com/aus-der-Technik/swifty-nats/actions/workflows/linux.yml/badge.svg?branch=main)](https://github.com/aus-der-Technik/swifty-nats/actions/workflows/linux.yml)

Swift Version Compatibility: [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Faus-der-Technik%2Fswifty-nats%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/aus-der-Technik/swifty-nats)

Platform Compatibility: [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Faus-der-Technik%2Fswifty-nats%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/aus-der-Technik/swifty-nats)

## Support
Join the [#swift](https://natsio.slack.com/archives/C02D41BU0PQ) channel on nats.io Slack.
We'll do our best to help quickly. Also feel free to drop by to just say hi.
We'll do our best to help quickly. You can also just drop by and say hello. We're looking forward to developing the community.

## Installation
Use SPM to install this packages as a dependency in your projects `Package.swift` file .
Add the dependencies like below.
## Installation via Swift Package Manager
### In Package.swift
Add this packages as a dependency in your projects `Package.swift` file and add the Name to your target like shown in this example:

```swift

// swift-tools-version:5.4

import PackageDescription
Expand All @@ -25,7 +28,7 @@ let package = Package(
.executable(name: "YourApp", targets: ["YourApp"]),
],
dependencies: [
.package(name: "SwiftyNats", url: "https://github.com/aus-der-technik/swifty-nats.git", from: "2.1.1")
.package(name: "SwiftyNats", url: "https://github.com/aus-der-technik/swifty-nats.git", from: "2.2.0")
],
targets: [
.target(
Expand All @@ -36,32 +39,41 @@ let package = Package(
)

```
### In an .xcodeproj
Open the project inspector in XCode and select your project. It is importent to select the **project** and not a target!
Klick on the third tab `Package Dependencies` and add the git url `https://github.com/aus-der-technik/swifty-nats.git` by selecting the litte `+`-sign at the end of the package list.


## Basic Usage
```swift

import SwiftyNats

// register a new client
let client = NatsClient("http://nats.server:4222")

// listen to an event
client.on(.connect) { _ in
print("Client connected")
}

// try to connect to the server
try? client.connect()

// subscribe to a channel with a inline message handler.
client.subscribe("foo.bar") { message in
print("payload: \(message.payload)")
print("size: \(message.byteCount)")
print("reply subject: \(message.replySubject.subject)")
}

// publish an event onto the message strem into a subject
client.publish("this event happened", to: "foo.bar")

```

### Setting the loglevel

### Setting the loglevel
The default loglevel is `.error`. You can reset it to see more verbose messages. Possible
Values are `.debug`, `.info`, `.error` or `.critical`

Expand All @@ -70,6 +82,49 @@ let client = NatsClient("http://nats.server:4222")
client.config.loglevel = .info
```

### Reconnection is up to you
Reconnection is not part of this package, because if a server diconnects your application have to be sure that
subscribtions are made up again correctly.

With SwiftyNats this is a very easy step:

```swift

// register a new client
let client = NatsClient(url)

// listen to the .disconnected event to try a reconnect
client.on(.disconnected) { [self] _ in
sleep(5);
try? client.reconnect()
doSubscribe()
}

// subscribe to the channels
doSubscribe()

// private function to subscribe to channels
private func doSubscribe(){
client.subscribe("foo.bar") { message in
print("payload: \(message.payload)")
}
}
```

### List of events
The public class `NatsEvent` contains all events you can subscribt to.

| event | description |
| ------------ | ---------------------------------------------------------------------- |
| connected | The client is conected to the server. |
| disconnected | The client disconnects and was connectd before. |
| response | The client gets an response from the server (internal). |
| error | The server sends an error that can't be handled. |
| dropped | The clients droped a message. Mostly because of queue length to short. |
| reconnecting | The client reconencts to the server, (Because of a called reconnect()).|
| informed | The server sends his information data successfully to the client. |


### Information about the connected server

Since 2.0.2 it is possible to get the informations from the conencted server
Expand All @@ -79,25 +134,23 @@ let client = NatsClient("http://nats.server:4222")
print("\(client.serverInformation.serverName) has Version: \(client.serverInformation.version))");
```

## Why does this project exist?
Ray Krow created the basis for this project in his [original repository](https://github.com/rayepps/swifty-nats).
There hasn't been much activity for years, and times change, so swift do. I have tried to use his code from
version 1.3.1, but it didn't work on Linux, or with Nats 2.1.7, or with NIO2. There was
also a bug in his code that did not parse messages on a busy server (dropped messages).
So I decided to fork his repository and change a few small things first to get the code working again.
While spending some time in the code, I realized I wanted a few things different and found myself
myself deeply into maintaining the nats swift community.

So I commit: I will maintain this package and optimize it for modern swift and most current NATS servers. Please
join the [#swift](https://natsio.slack.com/archives/C02D41BU0PQ) channel on nats.io Slack to discuss features and improvements with me.


## Contribution
Contribution is always welcome. Just send me a pull request.


# Changelog

## 2.2.0
- The client configuration is now publicly available
- The handling of the connection status has been rewritten
- Rewrite of the connection setup
- The connection termination was rewritten
- All classes have been cleaned up (refactoring)
- A new license was added (BSD-0)
- The reconnection code was removed
- Subscription queue is an optional property of NatsSubject

## 2.1.1
- rewrite the ChannelHandler: remove a bug that could lead into dropped messages.

Expand Down
9 changes: 5 additions & 4 deletions Sources/SwiftyNats/Extensions/Data+String.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
// Data+String.swift
// SwiftyNats
//
// Created by Ray Krow on 2/27/18.
//

import Foundation
import NIOPosix

extension Data {
func toString() -> String? {
guard let nss = NSString(data: self, encoding: String.Encoding.utf8.rawValue) else { return nil }
return String(describing: nss)
if let str = String(data: self, encoding: .utf8) {
return str
}
return nil
}
}
7 changes: 0 additions & 7 deletions Sources/SwiftyNats/Extensions/Streams+Read+Write.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@
// Streams+Read+Write.swift
// SwiftyNats
//
// Created by Ray Krow on 2/27/18.
//

import Foundation

extension InputStream {

func readStream() -> Data? {

let max_buffer = 4096
var dataQueue = [Data]()
var length = max_buffer
Expand All @@ -26,13 +23,11 @@ extension InputStream {
}

guard !dataQueue.isEmpty else { return nil }

let data = dataQueue.reduce(Data(), {
var combined = Data(referencing: NSData(data: $0))
combined.append($1)
return combined
})

return data
}

Expand All @@ -43,10 +38,8 @@ extension InputStream {
}
if (self.streamError != nil) { break }
}

return nil
}

}

extension OutputStream {
Expand Down
8 changes: 0 additions & 8 deletions Sources/SwiftyNats/Extensions/String+Utilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// String+Utilities.swift
// SwiftyNats
//
// Created by Ray Krow on 2/27/18.
//

import Foundation

Expand All @@ -24,12 +22,6 @@ extension String {
return String(self[start...end])
}

subscript (bounds: CountableRange<Int>) -> String {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return String(self[start..<end])
}

func removeNewlines() -> String {
return self.components(separatedBy: CharacterSet.newlines).reduce("", {$0 + $1})
}
Expand Down
17 changes: 11 additions & 6 deletions Sources/SwiftyNats/NatsClient/NatsClient+ChannelHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// NatsClient+ChannelInboundHandler.swift
// SwiftyNats
//
// by aus der Technik, 2021
//

import Foundation
import NIO
Expand All @@ -14,6 +12,8 @@ extension NatsClient: ChannelInboundHandler {

public func channelActive(context: ChannelHandlerContext) {
logger.debug("Channel gets active")

self.state = .connected
inputBuffer = context.channel.allocator.buffer(capacity: 512)
}

Expand Down Expand Up @@ -53,20 +53,25 @@ extension NatsClient: ChannelInboundHandler {
}

public func channelInactive(context: ChannelHandlerContext) {
logger.debug("NIO channel gets inactive")
logger.debug("Channel gets inactive")
context.close(promise: nil)

self.state = .disconnected
}

public func channelRead(context: ChannelHandlerContext, data: NIOAny) {
logger.debug("NIO channel read ")
logger.debug("Channel read")
var byteBuffer = self.unwrapInboundIn(data)
inputBuffer?.writeBuffer(&byteBuffer)
}

public func errorCaught(context: ChannelHandlerContext, error: Error) {
logger.error("Error caught: \(error.localizedDescription)")
self.disconnect()

context.close(promise: nil)
self.fire(.disconnected)
self.disconnect()

self.state = .disconnected
}
}

Expand Down

0 comments on commit 85d0bf4

Please sign in to comment.