Giter VIP home page Giter VIP logo

eventsource's Introduction

EventSource

EventSource

SSE Client written on Swift using NSURLSession.

Build Status codecov.io codecov.io

Abstract

This is an EventSource implementation written on Swift following the W3C EventSource document. If something is missing or not completely right open an issue and I'll work on it!

If you like the library please leave us a ★. That helps us to stay engaged on the mantainence!

Changes from version 2.2.1 to 3.0

I took some time to review all the forks, pull requests and issues opened on github. The main changes and complains I found were related to the connection and the Last-Event-Id handling.

The changes on this version are:

  • EventSource doesn't connect automatically anymore. It waits until connect(lastEventId: String? = nil) method is called. This method accepts a lastEventId which will be sent to the server upon connection.
  • EventSource lets you call disconnect() whenever you want.
  • EventSource doesn't store the Last-Event-Id anymore and you will have to take care of storing the id and sending using it or not in the connect method.
  • EventSource doesn't reconnect at all. If a network layer error occurs (disconnection, timeout, etc) or if the server closes the connection you will have to take care to reconnect with the server.
  • Modularization. This library has been around since Swift 1.0 and started just as a way to learn the language. With this new version the whole code has been improved, commented and fully tested to make it easier to track problems and extend in the future.

How to use it?

There is a simple working sample in the repository. Check the ViewController.swift to see how to use it.

Also in sse-server folder you will find an extremely simple node.js server to test the library. To run the server you just need to:

  • npm install
  • node sse.js

Install

Cocoapods

  1. Include EventSource in your Podfile: pod 'IKEventSource'

  2. Import the framework:

import IKEventSource

Carthage

  1. Include EventSource in your Cartfile: github "inaka/EventSource"

  2. Import the framework:

import IKEventSource

For further reference see Carthage's documentation.

Swift Package Manager

  1. Include EventSource in your Package.swift: github "inaka/EventSource"
import PackageDescription

let package = Package(
dependencies: [
    .package(url: "https://github.com/inaka/EventSource.git", .branch("master"))
])
  1. Import the framework:
import IKEventSource

Swift API:

/// RetryTime: This can be changed remotly if the server sends an event `retry:`
var retryTime: Int { get }

/// URL where EventSource will listen for events.
var url: URL { get }

/// The last event id received from server. This id is neccesary to keep track of the last event-id received to avoid
/// receiving duplicate events after a reconnection.
var lastEventId: String? { get }

/// Current state of EventSource
var readyState: EventSourceState { get }

/// Method used to connect to server. It can receive an optional lastEventId indicating the Last-Event-ID
///
/// - Parameter lastEventId: optional value that is going to be added on the request header to server.
func connect(lastEventId: String?)

/// Method used to disconnect from server.
func disconnect()

/// Returns the list of event names that we are currently listening for.
///
/// - Returns: List of event names.
func events() -> [String]

/// Callback called when EventSource has successfully connected to the server.
///
/// - Parameter onOpenCallback: callback
func onOpen(_ onOpenCallback: @escaping (() -> Void))

/// Callback called once EventSource has disconnected from server. This can happen for multiple reasons.
/// The server could have requested the disconnection or maybe a network layer error, wrong URL or any other
/// error. The callback receives as parameters the status code of the disconnection, if we should reconnect or not
/// following event source rules and finally the network layer error if any. All this information is more than
/// enought for you to take a decition if you should reconnect or not.
/// - Parameter onOpenCallback: callback
func onComplete(_ onComplete: @escaping ((Int?, Bool?, NSError?) -> Void))

/// This callback is called everytime an event with name "message" or no name is received.
func onMessage(_ onMessageCallback: @escaping ((_ id: String?, _ event: String?, _ data: String?) -> Void))

/// Add an event handler for an specific event name.
///
/// - Parameters:
///   - event: name of the event to receive
///   - handler: this handler will be called everytime an event is received with this event-name
func addEventListener(_ event: String,
                      handler: @escaping ((_ id: String?, _ event: String?, _ data: String?) -> Void))

/// Remove an event handler for the event-name
///
/// - Parameter event: name of the listener to be remove from event source.
func removeEventListener(_ event: String)

Examples:


Event:

id: event-id
event: event-name
data: event-data

Calls

eventSource.addEventListener("event-name") { (id, event, data) in
  // Here you get an event 'event-name'
}

Event:

id: event-id
data: event-data
data: event-data

Calls

eventSource.onMessage { (id, event, data) in
  // Here you get an event without event name!
}

Event:

id: event-id
data: event-data-1
data: event-data-2
data: event-data-3

Calls

eventSource.onMessage { (id, event, data) in
  // Here you get an event without event name!
  // data: event-data-1\nevent-data-2\nevent-data-3
}

Event:

:heartbeat

Calls

nothing it's a comment

Live example

This is the example shipped with the app. If you run the server and run the app you will be able to see this example live. The moving box is just to show that everything works on background and the main thread performance shows no degradation. (The gif is pretty bad to see that, but if you click on the image you will be taken to the gfycat version of the gif which runs way smoother)

Sample

Contributors

Thanks to all the contributors for pointing out missing stuff or problems and fixing them or opening issues!!

Contact Us

If you find any bugs or have a problem while using this library, please open an issue in this repo (or a pull request :)).

Please provide an example of the problem you are facing. If an event is not correctly parsed please provide a sample event.

eventsource's People

Contributors

agerace avatar alexocode avatar alexpalman avatar andresinaka avatar blueprajna avatar chrux avatar col avatar elbrujohalcon avatar gardano avatar hermanbanken avatar heyzooi avatar hleinone avatar igaray avatar joekelly10 avatar pengzishangtest avatar robbiet480 avatar spike886 avatar tbaranes avatar vincedev avatar volbap avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

eventsource's Issues

Cannot inherit from non-open class

Thanks for implementing much needed iOS feature.

I've been using v'2.2.1' in which "EventSource" was an open class. It helped me to bypass SSL validation in development environment and custom logging by subclassing. This behaviour allowed us to add much more.

Example:

    // MARK: URLSessionTaskDelegate Functions
    override func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
        super.urlSession(session, dataTask: dataTask, didReceive: data)
        LogUtil.logInfo("𐄖 SSE -> didReceive data: \(String(data: data, encoding: .utf8))", shouldLog: MyEventSource.shouldLog)
    }
    
    func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        LogUtil.logInfo("session: \(session); \n task: \(task); \n challenge: \(challenge)", shouldLog: MyEventSource.shouldLog)
        if case .dev = self.config {
            completionHandler(.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
        }
        else {
            completionHandler(.performDefaultHandling, nil)
        }
    }

In v'3.0.0' it has been made as public which blocks wrapping. Please make the class and required functions open again.

Pod don't create target

There is a pod 'IKEventSource' line in the Podfile
In console it prints Using IKEventSource (2.0.0)
But in Xcode there are no target for this pod.
2018-05-17 10 40 47

I did pod deintegrate -> pod update but still no effect.

Error connect/disconnect textfiled textChanged

Hello,

I have to display informations wheb user changed text in a textfield and I have to disconnect and reconnect with the new value .
In this moment I received informations also for the preview input value (the result contains informations for both inputs).
Any sugestions for this situation ?

NSRangeException

Sometimes, my app crashes and give me smth like this:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSConcreteMutableData rangeOfData:options:range:]: range {588, 18446744073709551038} causes integer overflow'
*** First throw call stack:
(0x18240b164 0x181654528 0x18240b0ac 0x182d98a54 0x10131ffcc 0x10131f9d8 0x10131e9fc 0x10131eaec 0x182b47970 0x182de1ba0 0x182d21894 0x182d114c4 0x10401d28c 0x1040299e4 0x10401d28c 0x1040299e4 0x1040298a4 0x182de3878 0x10401d28c 0x10402a678 0x104028f08 0x10402e9d0 0x10402e6f4 0x18203306c 0x182032b6c)
libc++abi.dylib: terminating with uncaught exception of type NSException

What you can tell me about this?

Cannot access stream data even though server connection established

I'm using nodejs with express on my server and authenticating users with token. Eventsource can establish connection to my server but I cannot access server event data even though I exactly copied the sse.js code just to test. Here is authentication code;

let token = "Bearer tokenWithSecret"
self.eventSource = EventSource(url:server , headers: ["Authorization" : token])

self.eventSource?.onOpen {
print("onOpen")
}
onOpen callback works fine but others are not working. Funny side is nodejs client is working and getting server events properly.

Custom NSURLSessionConfiguration

ATM it's not possible to customise the NSURLSessionConfiguration. I thought about creating a pull request but I'm not sure what approach would make sense to allow the user to customise the configuration.

Our specific problem resolves around cookies; the service we use sets a session cookie which is undesirable as we want a "fresh" connection every time, since the service sends the initial system state at the beginning.

Any ideas on how this can be implemented?

Will first several small Events be cached?

Hello,
I am using EventSource in a Swift iOS project, I found the Callback functions could not be called immediately just when Event be received by client which send from server (can be seen in Wireshark). But after several Event be received, action of Callback functions become normal. I think first several bytes of data which have received by client could be cached by URLSession? How to prevent it?

Suscribed Events list

Should we have a way to get the events we already subscribed to with the addEventListener method? @elbrujohalcon , what do you think about this? Also i think we don't have a removeEventListener method to unsubscribe events.

Firebase observer using REST Api

I am building IOS application using firebase REST API. From the doc (Ref: https://firebase.google.com/docs/reference/rest/database/) it says that we can Stream from the REST API.I am not able to listen firebase events.When I run the app Only onOpen callback is called. When i changed the child value on firebase nothing happened on callback methods. Can you suggest me the way to observe the events?

I tried following code:

   Auth.auth().currentUser?.getIDTokenForcingRefresh(true, completion: { (token, error) in
    let server : String =  "https://project-XXXXX.firebaseio.com/.json?auth=\(token!)"

    let eventSource: EventSource = EventSource(url: server)
    eventSource.onOpen {
        // When opened
        debugPrint("eventSource open")
    }

    eventSource.onError { (error) in
        // When errors
        debugPrint("error = \(error?.localizedDescription)")
    }
    eventSource.onMessage { (id, event, data) in
         debugPrint("data = \(data)")
        // Here you get an event without event name!
    }

    eventSource.addEventListener("child_added") { (id, event, data) in
           debugPrint("data = \(data)")
        // Here you get an event 'event-name'
    }
})

Swift 5 and XCode 11 compatibility

I want to update my project to swift 5 and XCode 11, and wish to know if you guys are already planning on launching a version to conform with the newer Swift and XCode. Thanks!

Typo in README

when using your framework, I should type
import EventSource
instead of
import IKEventSource

This typo is quite confusing for a beginner like me. Would you mind fix it?

Carthage: Dependency "EventSource" has no shared framework schemes

I get this error when installing from Carthage:

*** Skipped building EventSource due to the error:
Dependency "EventSource" has no shared framework schemes
    
If you believe this to be an error, please file an issue with the maintainers at https://github.com/inaka/EventSource/issues/new

Perhaps this SO is helpful?

https://stackoverflow.com/questions/35054788/carthage-no-shared-framework-schemes-for-ios-platform-for-my-own-framework

When does onOpen run?

Hello,
I am attempting to connect to an SSE server that separately also supplies data to a different project. When I attempt to connect to the server, onOpen() never runs, but onComplete does when I disconnect. Whats odd is that if I change the URL to be something definitely wrong, onOpen does run. Does onOpen() only run once a message fitting the current listeners is received?
My current guess is that its connecting properly but if it never received a message that fit the listeners it wouldn't open?

Console with correct URL:
Console with Correct URL
Console with incorrect URL:
Console with Incorrect URL

My code:
Screen Shot 2019-10-25 at 1 09 12 PM

Optional/empty headers

Can we change the init method of the EventSource class
public init(url: String, headers: [String : String]) { }
So it has an empty array by default ?
Something like :
public init(url: String, headers: [String : String] = [:]) { }

I encountered issues trying to submit the app this way

Hello @andresinaka ,

While uploading the application, i'm facing the following issue:

ERROR ITMS-90171: "Invalid Bundle Structure - The binary file 'myapp.app/Frameworks/IKEventSource.framework/IKEventSource' is not permitted. Your app can’t contain standalone executables or libraries, other than a valid CFBundleExecutable of supported bundles. Refer to the Bundle Programming Guide at https://developer.apple.com/go/?id=bundle-structure for information on the iOS app bundle structure."

I'm using Xcode 11.1 to upload the app.
Can anyone please help me to resolve this.

Thanks!

Support HTTP 204 response for no content

In cases where a server is sending a stream of content and wishes to end and close the connection, the current implementation will continue to reconnect.

Per the the spec at http://www.w3.org/TR/eventsource/:
Clients will reconnect if the connection is closed; a client can be told to stop reconnecting using the HTTP 204 No Content response code.

EventSource should support this feature and cease reconnecting if it tries to reconnect and receives a 204 response.

Swift 3 release

Hello EventSource team,

I noticed, that the PR with all the Swift 3 changes was merged, but there is still no tag for the most fresh version, so I would be able to use it via CocoaPods. Can it be created? If not, maybe you need some help there as my project depends on it.

`IKEventSource` does not specify a Swift version

Projects which have been written purely in ObjC face this issue while installing EventSource using CocoaPods.

Error Log:

[!] Unable to determine Swift version for the following pods:

  • IKEventSource does not specify a Swift version and none of the targets (<ProjectName>) integrating it have the SWIFT_VERSION attribute set. Please contact the author or set the SWIFT_VERSION attribute in at least one of the targets that integrate this pod.

Adding s.swift_version = 'version' in podspec will solve the issue, I guess.

OnError is called with no errror

It is working completely fine with Curl. But in swift it keeps getting an error without any reason why.

CULR curl --get http://ec2-54-86-125-75.compute-1.amazonaws.com:9000/v1/event-feed/game/f3bcd4e6-0b1f-4169-965e-4276035d64f1

Displays:

event: GameEnded
id: 1509124395663
data: {"id":1509124395663,"gameId":"f3bcd4e6-0b1f-4169-965e-4276035d64f1"}

`

let gameUrl = "http://ec2-54-86-125-75.compute-1.amazonaws.com:9000/v1/event-feed/game/f3bcd4e6-0b1f-4169-965e-4276035d64f1"
self.eventSource = EventSource.init(url: gameUrl)
            self.eventSource?.onOpen {
                // When opened
                print("opened")
            }
            self.eventSource?.onError { (error) in
                // When errors
                print(error)
                print(self.eventSource?.description)
                print(self.eventSource?.debugDescription)

            }
            
            self.eventSource?.onMessage { (id, event, data) in
                // Here you get an event without event name!
                print(data)
            }
            
            self.eventSource?.addEventListener("event-name") { (id, event, data) in
                // Here you get an event 'event-name'
                print(data)

            }
`

Not buffering data between URLSession didReceiveData callbacks.

The URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) method doesn't provide any guaranties about how much data will be returned each time it's called.

It may include half an event, or one and a half events, or 5 events. You need to make sure you store the data between calls and only process each event once you've received the delimiter.

Remove the IK prefix from everywhere

The IK prefix is still present in some places (the pod name, for example, is still IKEventSource). It should be removed from everywhere to keep consistency with the current name of the library, which is EventSource.

no ios scheme on tags versions

Hi, carthage doesn't want to build ios, because for ex in tag "3.0.1" doesn't exist ios scheme... In master it have. Please add this scheme to new version :)

close connection

how can i check event source is alredy open or not and close the old connection and open the new connection ??Hi Please help on this

init with Header method not found in Fremework. When i integrated using podfile

Hi, I integrated the EventSource pod using

pod 'EventSource'

But i did not find init with header method

public init(url: String, headers: [String : String] = [:]) {} in the framework. But i could see that method in sample app which you provided. Currently using EventSource (1.0.4). Am i using correct version ? where else going wrong?

SPM Support

I think it would be useful to add SPM support. I don't use any third party package managers and this library is great!

greetings, krjw

Importing problem in Swift

When I install via cocoa pods, as in your instruction, I cannot import the module, concretely, I get the message No such module 'EventSource’

Do you have any ideas?

Expose to Objective C

I have a project that requires me to consume all pods with Objective C. Since Swift >= 4 requires the explicit setting of the @objc attribute to expose Swift methods to Objective C I'm currently unable to use EventSource unless I maintain my own fork with the attributes added.

Would you be open to a pull request that adds the @objc attribute to the methods of EventSource? I've looked into it and the only method that won't be as simple as adding @objc is onComplete. This is due to its usage of Bool? and Int? in the function definition. For that method I would propose a new wrapper method be created called onCompleteBridged that would be exposed to Objective C and would handle unwrapping the props to Objective C compatible NSNumber?

Not able to connect SSE Url with headers

I am getting following URL Error Domain=kCFErrorDomainCFNetwork Code=303 "(null)" UserInfo={NSErrorPeerAddressKey=<CFData 0x1c0289e70 [0x1b5a22310]>{length = 16, capacity = 16, bytes = 0x100201bb0fce90590000000000000000}, _kCFStreamErrorCodeKey=-2201, _kCFStreamErrorDomainKey=4} When I try to hit URL with header ( User agent, Authorisation). It is not connecting only. After sometime disconnected call will happen. It will be really helpful if somebody guide me on this

onOpen-onError is cyclically called

What could be the cause of this problem? The EventSource reconnects, but an error always occurs and an onError is called, and the error = nil.

Fulfil the open-source checklist

General Items

  • It has a github repo
  • It has a proper LICENSE file
  • It's hooked to a hipchat room
  • It's has a clear and useful README.md
  • It's documented (with examples)
  • It's tested

Exhibition

  • There is a blog post about it
  • It's shared on social networks
  • It's shared on reddit
  • It's shared on hacker news with a title like Show HN: description
  • It has a landing page built in github pages

For Libraries

  • It provides a sample application
  • Examples of use are documented in the README or linked from there

For iOS Libraries

  • It is podyfied

macOS support?

Hi there,

Running carthage update --platform macOS results in:

Dependency "EventSource" has no shared framework schemes for any of the platforms: Mac

The readme does not mention that EventSource is a iOS only framework.
Will it run on Mac?

thanks in advance

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.