Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LiveQuery Support #45

Merged
merged 53 commits into from
Jan 10, 2021
Merged

LiveQuery Support #45

merged 53 commits into from
Jan 10, 2021

Conversation

cbaker6
Copy link
Contributor

@cbaker6 cbaker6 commented Jan 4, 2021

Minimum requirements to use LiveQuery are: macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0

Was able to reuse some of the ParseLiveQuery-iOS SDK.

This is a work in progress...

  • LiveQuerySocket - Uses URLSessionWebSocket hence the minimum requirements above... Uses a dedicated session URLSession.liveQuery. Supports multiple connections to different servers
  • Delegate authentication challenges to the developer. They can do their own cert pinning and auth if they want. If no authentication provided, will default to OS auth.
  • (Parse) All parse network calls now have a dedicated session, URLSession.parse which delegates authentication challenges also. LiveQuery will default to the parse authentication challenge if one isn't specified in the LiveQuery delegate.
  • (Parse) Use POST instead of GET for user login
  • LiveQuery Subscribe/Unsubscribe/Update
  • LiveQuery Events
  • Documentation
  • Playground examples
  • Testcases for encoding/decoding, states

@cbaker6 cbaker6 marked this pull request as draft January 4, 2021 02:51
@codecov
Copy link

codecov bot commented Jan 4, 2021

Codecov Report

Merging #45 (b58fb67) into main (f124d0a) will increase coverage by 0.12%.
The diff coverage is 71.35%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #45      +/-   ##
==========================================
+ Coverage   76.53%   76.65%   +0.12%     
==========================================
  Files          35       42       +7     
  Lines        3239     3757     +518     
==========================================
+ Hits         2479     2880     +401     
- Misses        760      877     +117     
Impacted Files Coverage Δ
Sources/ParseSwift/Storage/KeychainStore.swift 97.75% <ø> (ø)
...rces/ParseSwift/Storage/PrimitiveObjectStore.swift 88.00% <ø> (ø)
...t/LiveQuery/Protocols/ParseLiveQueryDelegate.swift 20.00% <20.00%> (ø)
...urces/ParseSwift/API/ParseURLSessionDelegate.swift 24.13% <24.13%> (ø)
Sources/ParseSwift/Types/Query.swift 91.54% <50.00%> (+4.49%) ⬆️
Sources/ParseSwift/LiveQuery/LiveQuerySocket.swift 61.40% <61.40%> (ø)
Sources/ParseSwift/LiveQuery/Subscription.swift 63.26% <63.26%> (ø)
Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift 74.73% <74.73%> (ø)
Sources/ParseSwift/API/URLSession+extensions.swift 78.04% <75.00%> (+16.75%) ⬆️
Sources/ParseSwift/API/API+Commands.swift 80.75% <100.00%> (+3.32%) ⬆️
... and 14 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f124d0a...b58fb67. Read the comment docs.

@cbaker6
Copy link
Contributor Author

cbaker6 commented Jan 8, 2021

@TomWFox can you review the docs? This PR is moving into testing.

@cbaker6
Copy link
Contributor Author

cbaker6 commented Jan 8, 2021

@pmmlo Can you test this locally?

I have a server setup via docker that will work out-of-the box with the Playgrounds files if you need it. It also gives you dashboard so you can add/remove/edit fields in there. Clone, and type docker-compose up. I usually select the "Mac OS" framework when testing in Playgrounds, the iOS one messes up sometimes and asks for entitlements.

The Playgrounds file with how to use LiveQuery is here:

//: Create a query just as you normally would.
var query = GameScore.query("score" > 9)
//: This is how you subscribe your created query
let subscription = query.subscribe!
//: This is how you receive notifications about the success
//: of your subscription.
subscription.handleSubscribe { subscribedQuery, isNew in
//: You can check this subscription is for this query\
if isNew {
print("Successfully subscribed to new query \(subscribedQuery)")
} else {
print("Successfully updated subscription to new query \(subscribedQuery)")
}
}
//: This is how you register to receive notificaitons of events related to your LiveQuery.
subscription.handleEvent { _, event in
switch event {
case .entered(let object):
print("Entered: \(object)")
case .left(let object):
print("Left: \(object)")
case .created(let object):
print("Created: \(object)")
case .updated(let object):
print("Updated: \(object)")
case .deleted(let object):
print("Deleted: \(object)")
}
}
//: Now go to your dashboard, goto the GameScore table and add, update, remove rows.
//: You should receive notifications for each.
//: This is how you register to receive notificaitons about being unsubscribed.
subscription.handleUnsubscribe { query in
print("Unsubscribed from \(query)")
}
//: To unsubscribe from your query.
do {
try query.unsubscribe()
} catch {
print(error)
}

From what I've seen Subscribe and all of the Events seem to work fine.

I broke something in unsubscribe and update, but it's probably an easy fix I'l get to later.

@cbaker6
Copy link
Contributor Author

cbaker6 commented Jan 10, 2021

@pranjalsatija can you review?

Copy link
Contributor

@TomWFox TomWFox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only being picky really...

cbaker6 and others added 4 commits January 10, 2021 14:27
Co-authored-by: Tom Fox <13188249+TomWFox@users.noreply.github.com>
Co-authored-by: Tom Fox <13188249+TomWFox@users.noreply.github.com>
Co-authored-by: Tom Fox <13188249+TomWFox@users.noreply.github.com>
@cbaker6 cbaker6 merged commit 9575409 into main Jan 10, 2021
@cbaker6 cbaker6 deleted the liveQuery branch January 10, 2021 20:17
@pmmlo
Copy link
Contributor

pmmlo commented Jan 16, 2021

@cbaker6 I had a little time to test this with a HTTPS server and .subscribe and .handleSubscribe return expected callbacks. However, after about ~29s (timed twice, but seems consistent), I get these two errors:

2021-01-15 16:12:45.010269-0800 Member[60224:14126091] [tcp] tcp_input [C1.1:3] flags=[R] seq=3454113186, ack=0, win=0 state=LAST_ACK rcv_nxt=3454113186, snd_una=1642147939
2021-01-15 16:12:45.011230-0800 Member[60224:14126091] [tcp] tcp_input [C1.1:3] flags=[R] seq=3454113186, ack=0, win=0 state=CLOSED rcv_nxt=3454113186, snd_una=1642147939
2021-01-15 16:12:45.012326-0800 Member[60224:14126091] [tcp] tcp_input [C1.1:3] flags=[R] seq=3454113186, ack=0, win=0 state=CLOSED rcv_nxt=3454113186, snd_una=1642147939

It seems like the Subscription is timing out or crashing. I have guesses on what may be going on but thought you may know immediately.

Here's the code:

query = Team.query("member" == User.current?.objectId)
guard let subscription = query.limit(1).subscribe else { return }

subscription.handleSubscribe { subscribedQuery, isNew in
    if isNew {
        print("Successfully subscribed to new query \(subscribedQuery)")
    } else {
        print("Successfully updated subscription to new query \(subscribedQuery)")
    }
}

subscription.handleEvent { _, event in
    print("\(event)")
    switch event {
    case .entered(let object):
        print("Entered: \(object)")
    case .left(let object):
        print("Left: \(object)")
    case .created(let object):
        print("Created: \(object)")
    case .updated(let object):
        print("Updated: \(object)")
    case .deleted(let object):
        print("Deleted: \(object)")
    }
}

 subscription.handleUnsubscribe { query in
    print("Unsubscribed from \(query)")
}

I never receive any events, despite editing in dashboard. I can unsubscribe with the expected response before the two errors fire.

Any ideas?

@cbaker6
Copy link
Contributor Author

cbaker6 commented Jan 16, 2021

Did you register your Team class for LiveQuery in your index file of your Parse Server? The subscription should go through immediately.

liveQuery: {
    classNames: ["GameScore", "Book", "Author"] // List of classes to support for query subscriptions
  },

I tested this LiveQuery by leaving a subscriptions on over night in the simulator for an iPhone and Apple Watch and it didn't disconnect and sent events the next day.

@cbaker6
Copy link
Contributor Author

cbaker6 commented Jan 16, 2021

You can see how I setup the server for playgrounds here: https://github.com/netreconlab/parse-hipaa/blob/parse-swift/parse/index.js

Also, for your server, are you behind a proxy? If you are using Nginx be sure to setup https://www.nginx.com/blog/websocket-nginx/

@pmmlo
Copy link
Contributor

pmmlo commented Jan 16, 2021

You can see how I setup the server for playgrounds here: https://github.com/netreconlab/parse-hipaa/blob/parse-swift/parse/index.js

I have something similar with Express as well. I also ensured livequery server was initialized and the Team class name was listed.

I guess not as straight forward as I thought it would be. I will dig into this then. Must be an implementation issue.

@pmmlo
Copy link
Contributor

pmmlo commented Jan 16, 2021

Also, for your server, are you behind a proxy? If you are using Nginx be sure to setup https://www.nginx.com/blog/websocket-nginx/

I'm actually running it in a k8s cluster with an ingress. No Nginx proxy.

@cbaker6
Copy link
Contributor Author

cbaker6 commented Jan 16, 2021

But your http/localhost works when you use playgrounds and docker?

@pmmlo
Copy link
Contributor

pmmlo commented Jan 16, 2021

Yup. The remote works as well, even graphql.

@pmmlo
Copy link
Contributor

pmmlo commented Jan 16, 2021

I ran playgrounds using your docker and playgrounds. Worked well there.

@cbaker6
Copy link
Contributor Author

cbaker6 commented Jan 16, 2021

Maybe it's configuration, can you check if

components.scheme = (components.scheme == "https" || components.scheme == "wss") ? "wss" : "ws"

is converting your url to wss since you are tls?

@pmmlo
Copy link
Contributor

pmmlo commented Jan 16, 2021

Maybe it's configuration, can you check if

components.scheme = (components.scheme == "https" || components.scheme == "wss") ? "wss" : "ws"

is converting your url to wss since you are tls?

This looks promising. I think it may be...let me try to test this.

@pmmlo
Copy link
Contributor

pmmlo commented Jan 16, 2021

It's wss. Will need to checkout the ingress. Thanks!

@cbaker6
Copy link
Contributor Author

cbaker6 commented Jan 16, 2021

Are you able to connect using a site like https://www.websocket.org/echo.html

@pmmlo
Copy link
Contributor

pmmlo commented Jan 16, 2021

There was an undocumented backend timeout of 30 seconds in AWS that seems to have been the issue. Would have guessed 30 seconds was enough... Just raised it to 5 minutes, which should be more than enough. No error, but I'm still not getting anything from .handleEvent(). I'll play around with this and post, if I figure out my issue. ;)

@pmmlo
Copy link
Contributor

pmmlo commented Jan 16, 2021

Just started working after I put in breakpoints. Changed nothing, and I have an empty console. Maybe I should have cleaned the project first...

Sorry!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants