LiveQuery through REST, with ACL, back4app

362 views
Skip to first unread message

vis...@gmail.com

unread,
Jul 8, 2018, 5:09:37 AM7/8/18
to Back4App
Hi! I am trying to connect to LiveQuery using python, using REST api.
What I want, is to set an non public ACL to an object, log in with the user's credentials and subscribe with those credentials, to the object's changes.

What I tried (and worked):
I am using websockets library.
I can connect, register to changes, get event messages but only when the ACL for that object is public! [I used the URL: wss://_my_app_.back4app.io]

Connect and query that object (with user/pass credentials and private ACL of said object) using "regular" REST API. [I used the URL: https://parseapi.back4app.com/login to get the credentials and https://parseapi.back4app.com/classes/_my_app_/_objectId_ to get the data]

I tried, succesfully connected BUT failed to get event messages for private ACL object:
 * connecting to the LiveQuery websocket using the security headers from regular REST acces;
 * Using master key in the connect message
 * Using the previously got session token (from regular REST access)
None of above [or combinations] worked if the ACL was private.

I used this as a guideline:

1) Am I doing something wrong or there is no way to have ACL with LiveQuery?

2) If the resource is public, anybody with the URL can modify it through REST? Or they need to have at least the APP_ID or CLIENT_KEY? 

Thank you!

p.s. I googled a lot, with no luck

Cristi Vicas

unread,
Jul 8, 2018, 7:27:31 AM7/8/18
to Back4App
After some more permutations, this is what worked:

1) Log in to "regular" back4app auth endpoint:


head_login = {"X-Parse-Application-Id": APP_ID,
"X-Parse-REST-API-Key": REST_API_KEY,
"X-Parse-Revocable-Session": "1"}
login_params = {"username": USER_NAME, "password": PASSWD}
login_ans = requests.get("https://parseapi.back4app.com/login", params=login_params, headers=head_login)
session_token = login_ans.json()['sessionToken']

2) Connect to the webscoket endpoint: 


The "connect" op must contain: (or at least worked for me)

send_req = {
"op": "connect",
"applicationId": APP_ID,
"restAPIKey": REST_API_KEY,
}


And the subscribe message:

subscribe_op={
"op": "subscribe",
"requestId": 5,
"query": {
"className": "_your_class_", # without tariling /class/. Basically the name displayed in Browse section from Back4App Core browser
"where": {"objectId":"myobj"}, # some condition
"fields": ["name"] # fields that you want to watch
},
"sessionToken": session_token, # Must be present, it is not enough to put it in the connect message only.
                                     # Actually it is not needed at all in the connect.
}


So, the trick was to find the right combination of session tokens, various keys and URL endpoints. Helped a bit looking at the Android LiveQuery library, they always send the sessionToken with every subscribe message.

Hope it helps!

Cristi

cha...@back4app.com

unread,
Jul 9, 2018, 9:10:19 AM7/9/18
to Back4App
Hi!

Good to know that you were able to solve it. :D

Feel free to reach us whenever you need!

Regards,
Charles Ramos

Cristi Vicas

unread,
Sep 29, 2018, 2:19:50 AM9/29/18
to Back4App
Reminder: I used this setup for some time now, on a Raspberry, Python 3.4.3, and websockets library [ https://websockets.readthedocs.io/en/stable/intro.html ]

Basiclly, my LiveQuery listening loop is something like this:

# Login and and get the session_token as described in above posts
async with websockets.connect(LIVEQUERY_URL) as websocket:
    # Connect
    # Subscribe
    while(1)
        
recv_event = await websocket.recv()
        # handle execption in recv()
        # handle zero length answer (just in case we are using an older websockets version)
        # handle 'op':'error'
 
        # handle 'op':'unsubscribed'
        # handle regular operations needed for the business logic.


What happens is that after a while (like 8-12hrs) the Back4App server does not send any new updates on the websocket. The websocket remains connected (no exceptions, no zero-length data received). From my side, the await recv() never receives anything, regardless of what is happening on the back4app tables. 
While the frequency of updates is rather small (few/hr at most) I can't pinpoint the exact moment when the connection is silently dropped.

For now, my solution to this is to send an unsubscribe message after some hours. Thanks to the async, I do it like this:

Prepare a coroutine that waits x seconds then sends the message. This coroutine has access to the websocket object above

async def cancel_connection():
    await asyncio.sleep(CONNECTION_TIMEOUT)
    await trigger_unsubscribe()  # sends the "op": "unsubscribe"
    await asyncio.sleep(3)
         await websocket.close()

and before while(1) listening loop:

asyncio.ensure_future(cancel_connection())

[Now, CONNECTION_TIMEOUT is set to 8hrs.]

It's been 2 days and for now, things are working (eg. I don't wake up in the morning and I find the connection silently dropped)

Any of you guys have any idea why the connection is silently dropped?


Thank you!


p.s. Maybe is relevant, maybe it is not. I think this behavior started 2-3 weeks ago after my back4app instance froze somehow and it was rebooted. 



On Sunday, July 8, 2018 at 12:09:37 PM UTC+3, Cristi Vicas wrote:

Cristi Vicas

unread,
Sep 29, 2018, 2:20:52 AM9/29/18
to Back4App
One little correction, python is 3.5.3


On Sunday, July 8, 2018 at 12:09:37 PM UTC+3, Cristi Vicas wrote:
Reply all
Reply to author
Forward
0 new messages