Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

cent

Package Overview
Dependencies
Maintainers
1
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cent - npm Package Compare versions

Comparing version
2.1.0
to
3.0.0
+111
README.md
CENT
====
Python tools to communicate with Centrifugo HTTP API. Python 2.6, Python 2.7 and Python >= 3.3 supported.
To install run:
```bash
pip install cent
```
### High-level library API
First see [available API methods in documentation](https://fzambia.gitbooks.io/centrifugal/content/server/api.html).
This library contains `Client` class to send messages to Centrifugo from your python-powered backend:
```python
from cent import Client
url = "http://localhost:8000"
api_key = "XXX"
# initialize client instance.
client = Client(url, api_key=api_key, timeout=1)
# publish data into channel
channel = "public:chat"
data = {"input": "test"}
client.publish(channel, data)
# other available methods
client.unsubscribe("USER_ID")
client.disconnect("USER_ID")
messages = client.history("public:chat")
clients = client.presence("public:chat")
channels = client.channels()
stats = client.info()
client.history_remove("public:chat")
```
`publish`, `disconnect`, `unsubscribe`, `history_remove` return `None` in case of success. Each of this commands can
raise an instance of `CentException`.
I.e.:
```python
from cent import Client, CentException
client = Client("http://localhost:8000", api_key="XXX", timeout=1)
try:
client.publish("public:chat", {"input": "test"})
except CentException:
# handle exception
```
Depending on problem occurred exceptions can be:
* RequestException – HTTP request to Centrifugo failed
* ResponseError - Centrifugo returned some error on request
Both exceptions inherited from `CentException`.
### Low-level library API:
To send lots of commands in one request:
```python
from cent import Client, CentException
client = Client("http://localhost:8000", api_key="XXX", timeout=1)
params = {
"channel": "python",
"data": "hello world"
}
client.add("publish", params)
try:
result = client.send()
except CentException:
# handle exception
else:
print result
```
You can use `add` method to add several messages which will be sent.
You'll get something like this in response:
```bash
[{}]
```
I.e. list of single response to each command sent. So you need to inspect response on errors (if any) yourself.
### Client initialization arguments
Required:
* address - Centrifugo address
Optional:
* api_key - HTTP API key of Centrifugo
* timeout (default: `1`) - timeout for HTTP requests to Centrifugo
* json_encoder (default: `None`) - set custom JSON encoder
* send_func (default: `None`) - set custom send function
* verify (default: `True`) - when set to `False` no certificate check will be done during requests.
+5
-3
Metadata-Version: 1.1
Name: cent
Version: 2.1.0
Summary: python tools to communicate with Centrifugo
Version: 3.0.0
Summary: Python library to communicate with Centrifugo API
Home-page: https://github.com/centrifugal/cent

@@ -10,3 +10,3 @@ Author: Alexandr Emelin

Download-URL: https://github.com/centrifugal/cent
Description: python tools to communicate with Centrifugo
Description: Python library to communicate with Centrifugo API
Platform: UNKNOWN

@@ -20,2 +20,4 @@ Classifier: Development Status :: 5 - Production/Stable

Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Environment :: Console

@@ -22,0 +24,0 @@ Classifier: Intended Audience :: Developers

@@ -1,1 +0,1 @@

requests
requests

@@ -0,4 +1,4 @@

README.md
setup.py
cent/__init__.py
cent/console.py
cent/core.py

@@ -5,0 +5,0 @@ cent.egg-info/PKG-INFO

# coding: utf-8
from .core import Client, CentException, RequestException, ResponseError, ClientNotEmpty, \
generate_api_sign, generate_channel_sign, generate_token, get_timestamp
from .core import Client, CentException, RequestException, ResponseError, ClientNotEmpty

@@ -8,6 +8,3 @@ # coding: utf-8

import sys
import hmac
import time
import json
from hashlib import sha256
import requests

@@ -57,53 +54,2 @@

def generate_token(secret, user, timestamp, info=""):
"""
When client from browser wants to connect to Centrifuge he must send his
user ID, timestamp and optional info. To validate that data we use HMAC
SHA-256 to build token.
@param secret: Centrifugo secret key
@param user: user ID from your application
@param timestamp: current timestamp seconds as string
@param info: optional json encoded data for this client connection
"""
sign = hmac.new(to_bytes(str(secret)), digestmod=sha256)
sign.update(to_bytes(user))
sign.update(to_bytes(timestamp))
sign.update(to_bytes(info))
token = sign.hexdigest()
return token
def generate_channel_sign(secret, client, channel, info=""):
"""
Generate HMAC SHA-256 sign for private channel subscription.
@param secret: Centrifugo secret key
@param client: client ID
@param channel: channel client wants to subscribe to
@param info: optional json encoded data for this channel
"""
auth = hmac.new(to_bytes(str(secret)), digestmod=sha256)
auth.update(to_bytes(str(client)))
auth.update(to_bytes(str(channel)))
auth.update(to_bytes(info))
return auth.hexdigest()
def generate_api_sign(secret, encoded_data):
"""
Generate HMAC SHA-256 sign for API request.
@param secret: Centrifugo secret key
@param encoded_data: json encoded data to send
"""
sign = hmac.new(to_bytes(str(secret)), digestmod=sha256)
sign.update(encoded_data)
return sign.hexdigest()
def get_timestamp():
"""
Returns current timestamp seconds string required to make connection to Centrifugo.
"""
return str(int(time.time()))
class Client(object):

@@ -114,12 +60,10 @@ """

def __init__(self, address, secret, timeout=1, send_func=None,
json_encoder=None, insecure_api=False, verify=True,
def __init__(self, address, api_key="", timeout=1,
json_encoder=None, verify=True,
session=None, **kwargs):
"""
:param address: Centrifugo address
:param secret: Centrifugo configuration secret key
:param api_key: Centrifugo API key
:param timeout: timeout for HTTP requests to Centrifugo
:param send_func: custom send function
:param json_encoder: custom JSON encoder
:param insecure_api: boolean value, when set to True no signing will be used
:param verify: boolean flag, when set to False no certificate check will be done during requests.

@@ -130,7 +74,5 @@ :param session: custom requests.Session instance

self.address = address
self.secret = secret
self.api_key = api_key
self.timeout = timeout
self.send_func = send_func
self.json_encoder = json_encoder
self.insecure_api = insecure_api
self.verify = verify

@@ -156,18 +98,4 @@ self.session = session or requests.Session()

address += api_path
address += "/"
return address
def sign_encoded_data(self, encoded_data):
return generate_api_sign(self.secret, encoded_data)
def prepare(self, data):
url = self.prepare_url()
encoded_data = to_bytes(json.dumps(data, cls=self.json_encoder))
if not self.insecure_api:
sign = self.sign_encoded_data(encoded_data)
else:
# no need to generate sign in case of insecure API option on
sign = ""
return url, sign, encoded_data
def add(self, method, params):

@@ -185,13 +113,18 @@ data = {

self._messages = []
if self.send_func:
return self.send_func(*self.prepare(messages))
return self._send(*self.prepare(messages))
url = self.prepare_url()
data = to_bytes("\n".join([json.dumps(x, cls=self.json_encoder) for x in messages]))
response = self._send(url, data)
return [json.loads(x) for x in response.split("\n") if x]
def _send(self, url, sign, encoded_data):
def _send(self, url, data):
"""
Send a request to a remote web server using HTTP POST.
"""
headers = {'Content-type': 'application/json', 'X-API-Sign': sign}
headers = {
'Content-type': 'application/json'
}
if self.api_key:
headers['Authorization'] = 'apikey ' + self.api_key
try:
resp = self.session.post(url, data=encoded_data, headers=headers, timeout=self.timeout, verify=self.verify)
resp = self.session.post(url, data=data, headers=headers, timeout=self.timeout, verify=self.verify)
except requests.RequestException as err:

@@ -201,3 +134,3 @@ raise RequestException(err)

raise RequestException("wrong status code: %d" % resp.status_code)
return json.loads(resp.content.decode('utf-8'))
return resp.content.decode('utf-8')

@@ -208,3 +141,3 @@ def reset(self):

@staticmethod
def get_publish_params(channel, data, client=None):
def get_publish_params(channel, data, uid=None):
params = {

@@ -214,8 +147,8 @@ "channel": channel,

}
if client:
params['client'] = client
if uid:
params['uid'] = uid
return params
@staticmethod
def get_broadcast_params(channels, data, client=None):
def get_broadcast_params(channels, data, uid=None):
params = {

@@ -225,4 +158,4 @@ "channels": channels,

}
if client:
params['client'] = client
if uid:
params['uid'] = uid
return params

@@ -256,2 +189,8 @@

@staticmethod
def get_history_remove_params(channel):
return {
"channel": channel
}
@staticmethod
def get_channels_params():

@@ -261,3 +200,3 @@ return {}

@staticmethod
def get_stats_params():
def get_info_params():
return {}

@@ -274,13 +213,13 @@

raise ResponseError(data["error"])
return data.get("body")
return data.get("result")
def publish(self, channel, data, client=None):
def publish(self, channel, data, uid=None):
self._check_empty()
self.add("publish", self.get_publish_params(channel, data, client=client))
self.add("publish", self.get_publish_params(channel, data, uid=uid))
self._send_one()
return
def broadcast(self, channels, data, client=None):
def broadcast(self, channels, data, uid=None):
self._check_empty()
self.add("broadcast", self.get_broadcast_params(channels, data, client=client))
self.add("broadcast", self.get_broadcast_params(channels, data, uid=uid))
self._send_one()

@@ -304,4 +243,4 @@ return

self.add("presence", self.get_presence_params(channel))
body = self._send_one()
return body["data"]
result = self._send_one()
return result["presence"]

@@ -311,15 +250,21 @@ def history(self, channel):

self.add("history", self.get_history_params(channel))
body = self._send_one()
return body["data"]
result = self._send_one()
return result["history"]
def history_remove(self, channel):
self._check_empty()
self.add("history_remove", self.get_history_remove_params(channel))
result = self._send_one()
return
def channels(self):
self._check_empty()
self.add("channels", self.get_channels_params())
body = self._send_one()
return body["data"]
result = self._send_one()
return result["channels"]
def stats(self):
def info(self):
self._check_empty()
self.add("stats", self.get_stats_params())
body = self._send_one()
return body["data"]
self.add("info", self.get_info_params())
result = self._send_one()
return result
Metadata-Version: 1.1
Name: cent
Version: 2.1.0
Summary: python tools to communicate with Centrifugo
Version: 3.0.0
Summary: Python library to communicate with Centrifugo API
Home-page: https://github.com/centrifugal/cent

@@ -10,3 +10,3 @@ Author: Alexandr Emelin

Download-URL: https://github.com/centrifugal/cent
Description: python tools to communicate with Centrifugo
Description: Python library to communicate with Centrifugo API
Platform: UNKNOWN

@@ -20,2 +20,4 @@ Classifier: Development Status :: 5 - Production/Stable

Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Environment :: Console

@@ -22,0 +24,0 @@ Classifier: Intended Audience :: Developers

[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0

@@ -17,3 +17,3 @@ import os

def long_description():
return "python tools to communicate with Centrifugo"
return "Python library to communicate with Centrifugo API"

@@ -23,4 +23,4 @@

name='cent',
version='2.1.0',
description="python tools to communicate with Centrifugo",
version='3.0.0',
description="Python library to communicate with Centrifugo API",
long_description=long_description(),

@@ -47,2 +47,4 @@ url='https://github.com/centrifugal/cent',

'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Environment :: Console',

@@ -49,0 +51,0 @@ 'Intended Audience :: Developers',

#!/usr/bin/env python
# coding: utf-8
from __future__ import print_function
import argparse
import os
import sys
import json
try:
import configparser as ConfigParser
except ImportError:
import ConfigParser
from .core import Client, CentException
def run():
parser = argparse.ArgumentParser(description='Centrifuge client')
parser.add_argument(
'section', metavar='SECTION', type=str, help='section key from cent configuration file'
)
parser.add_argument(
'method', metavar='METHOD', type=str, help='call method'
)
parser.add_argument(
'--params', type=str, help='params data', default='{}'
)
parser.add_argument(
'--config', type=str, default="~/.centrc", help='cent configuration file'
)
options = parser.parse_args()
config_file = os.path.expanduser(options.config)
config = ConfigParser.ConfigParser()
config.read(config_file)
if options.section not in config.sections():
print(
"Section {0} not found in {1} configuration file".format(
options.section, options.config
)
)
sys.exit(1)
try:
address = config.get(options.section, 'address')
secret = config.get(options.section, 'secret')
try:
timeout = config.getint(options.section, 'timeout')
except:
timeout = 1
except Exception as e:
print(e)
sys.exit(1)
if not sys.stdin.isatty():
json_data = sys.stdin.read().strip()
else:
json_data = options.params
if json_data:
try:
params = json.loads(json_data)
except Exception as e:
print(e)
sys.exit(1)
else:
params = {}
if not isinstance(params, dict):
print("params must be dictionary")
sys.exit(1)
client = Client(
address,
secret,
timeout=timeout
)
if not isinstance(params, dict):
print("params must be valid JSON object")
sys.exit(1)
client.add(options.method, params)
try:
result = client.send()
except CentException as err:
print(err.message)
sys.exit(1)
else:
print(result)
if __name__ == '__main__':
run()