How do I receive new responses in the Websocket? - python-3.x

I have a client module:
#!/usr/bin/env python
# WS client example
import asyncio
import websockets
async def hello():
async with websockets.connect(
'ws://A.B.C.D:8765') as websocket:
name = input("What's your name? ")
await websocket.send(name)
greeting = await websocket.recv()
print(greeting)
asyncio.get_event_loop().run_until_complete(hello())
and the server module:
from __future__ import print_function
#!/usr/bin/env python
import asyncio
import datetime
import random
import websockets
import ast
from collections import defaultdict
import csv
import datetime
from itertools import chain
import json
import os
import operator
import sys
import pymongo
from pymongo import MongoClient
try:
client = MongoClient('localhost', 27017)
db = client["Bubble"]
except Exception as e:
print(e)
start_match = datetime.datetime.strptime(
"2018-07-01 18:00:00", '%Y-%m-%d %H:%M:%S')
collection = "CRODEN_R16"
async def hello(websocket, path):
entity_name = await websocket.recv()
print(entity_name)
while True:
file = open("set_start_match.txt", "r")
for line in file:
start_today = datetime.datetime.strptime(
line.split('.')[0], '%Y-%m-%d %H:%M:%S')
print(start_today)
now = datetime.datetime.utcnow()
diff = now - start_today
request_match = start_match + diff
print(diff)
for post in db[collection].find():
if "emotion" not in post.keys():
print("Ignored")
continue
if post["timeStamp"] > request_match:
if post["entity_name"] == entity_name:
print("Satisfied")
currDict = {}
currDict["entity"] = post["entity_name"]
currDict["emotion"] = max(
post["emotion"].items(), key=operator.itemgetter(1))[0]
currDict["profile_image"] = post["userProfile"]
currDict["tweet"] = post["tweet"]
currDict_json = json.dumps(currDict, default=str)
print(currDict["tweet"])
await websocket.send(currDict_json)
await asyncio.sleep(1)
del currDict
try:
start_server = websockets.serve(hello, '0.0.0.0', 8765)
print("Start entity server")
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
except Exception as e:
print(e)
Now, the issue is that I want to send name as an input only once and receive the output continuously.
When I wrote this in client:
while True:
greeting = await.websocket.recv()
print(greeting)
The same response is returned again and again. Even on the server side, where I am printing the rendered results from db, I am printing the same doc.
I am completely clueless as to what is the issue?
Note: I have tried to the run the once-run client module and there I was getting perfect results. It was just that I had to give the same input again and again. I want it to be automated.

To get data continuously someone has to send data continuously.
If someone sends data continuously then someone else has to get data continuously.
So both sides need loop.
client - it sends numbers continuously in loop.
#!/usr/bin/env python
import asyncio
import websockets
import time
async def hello():
async with websockets.connect(
'ws://localhost:8769') as websocket:
name = input("What's your name? ")
await websocket.send(name)
i = 0
while True:
print('send:', i)
await websocket.send(str(i))
time.sleep(2)
i += 1
try:
asyncio.get_event_loop().run_until_complete(hello())
except KeyboardInterrupt:
print('KeyboardInterrupt')
server - it receives numbers continuously in loop
import asyncio
import websockets
async def hello(websocket, path):
entity_name = await websocket.recv()
print('name:', entity_name)
while True:
data = await websocket.recv()
print('recv:', data)
try:
print("Start entity server")
start_server = websockets.serve(hello, '0.0.0.0', 8769)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
except KeyboardInterrupt: # keyboard need special except
print("KeyboardInterrupt")
start_server.ws_server.close() # solutin for [Errno 98]
except Exception as ex:
print(ex)

Related

Telegram API Bot to invite subscribers of other channels to my own

I want to invite the members of other telegram channels to my channel, but getting this error
THE Error is:
raise ConnectionError('Connection to Telegram failed {} time(s)'.format(self._retries))
ConnectionError: Connection to Telegram failed 5 time(s)
I do not know why I am getting this error, I have checked it with a proxy but it remained the same.
If anyone of you know about this type of error please let me know. I have no idea about this. I do know about this. This is basically a telegram api bot that I want to be completely done with no errors.
import configparser
import json
import asyncio
import sys
import socks
from telethon import TelegramClient
from telethon.tl.types import InputPhoneContact
from telethon.tl.functions.contacts import ImportContactsRequest
from telethon.errors import FloodWaitError, RPCError
#import proxy
from telethon import TelegramClient
from telethon.errors import SessionPasswordNeededError
from telethon.tl.functions.channels import GetParticipantsRequest
from telethon.tl.types import ChannelParticipantsSearch
from telethon.tl.types import (
PeerChannel
)
# Reading Configs
config = configparser.ConfigParser()
config.read("config.ini")
# Setting configuration values
api_id = 1234567
api_hash = 'abcdefghjklmnopqrstuvwxyz1234567'
phone = '+123456789000'
username = '#abcdef'
#proxy='180.179.98.22:3128'
# Create the client and connect
client = TelegramClient(username, api_id, api_hash, proxy=(socks.SOCKS5, '166.62.80.198', 18726))
async def main(phone):
await client.start()
print("Client Created")
# Ensure you're authorized
if await client.is_user_authorized() == False:
await client.send_code_request(phone)
try:
await client.sign_in(phone, input('Enter the code: '))
except SessionPasswordNeededError:
await client.sign_in(password=input('Password: '))
me = await client.get_me()
user_input_channel = input("enter entity(telegram URL or entity id):")
if user_input_channel.isdigit():
entity = PeerChannel(int(user_input_channel))
else:
entity = user_input_channel
my_channel = await client.get_entity(entity)
offset = 0
limit = 100
all_participants = []
while True:
participants = await client(GetParticipantsRequest(
my_channel, ChannelParticipantsSearch(''), offset, limit,
hash=0
))
if not participants.users:
break
all_participants.extend(participants.users)
offset += len(participants.users)
all_user_details = []
for participant in all_participants:
all_user_details.append(
{"id": participant.id, "first_name": participant.first_name, "last_name": participant.last_name,
"user": participant.username, "phone": participant.phone, "is_bot": participant.bot})
with open('user_data.json', 'w') as outfile:
json.dump(all_user_details, outfile)
with client:
client.loop.run_until_complete(main(phone))

How to reconnect to a websocket when connection fails in python

Hi I created async websocket client which I can receive and send messages asynchronously.
Here is the clint class that I use.
import websockets
import asyncio
from models import Heartbeat
from model_helper import ModelHelper
from json_helper import JSONHelper
from os.path import dirname, abspath
import logging
import time
waiting_time = 0.5
class WebSocketClient():
def __init__(self, websocket_queue, configs):
self.Heartbeat = Heartbeat().message
self.websocket_queue = websocket_queue
self.configs = configs
def get_connection_string(self):
server_url = self.configs.URL + ":" + str(self.configs.Port) + self.configs.Root
return server_url
async def connect(self):
try:
server_url = self.get_connection_string()
self.connection = await websockets.client.connect(server_url)
if self.connection.open:
print("Connection stablished. Client correcly connected")
# Send greeting
await self.connection.send(self.Heartbeat)
return self.connection
else:
print("Can not connect")
except ConnectionRefusedError as err:
print("Connection Error: {}".format(err))
async def send_message_to_socket(self, connection):
while True:
message = self.websocket_queue.get_send_queue()
try:
if message is not None:
message_ = ModelHelper.to_outgoing_request_model(message)
await connection.send(message_)
else:
await asyncio.sleep(waiting_time)
except websockets.exceptions.ConnectionClosed:
print('Connection with server closed')
self.connect()
async def receive_message_from_socket(self, connection):
while True:
try:
message = await connection.recv()
obj = JSONHelper.toObject(message)
print("Received object from websocket: {}".format(obj))
#If a websocket entry has SendMessage in its Action property
#Consider it as an sms content to be sent.
if(obj.Action == "SendMessage"):
self.websocket_queue.add_received_queue(obj)
except websockets.exceptions.ConnectionClosed:
print('Connection with server closed1')
async def send_heartbeat_to_socket(self, connection):
while True:
#print("Heartbeat loop\n")
try:
await connection.send(self.Heartbeat)
await asyncio.sleep(3)
except websockets.exceptions.ConnectionClosed:
print('Connection with server closed2')
And this is the code where I listen for websocket messages:
def listen_websocket_routine(sms_queue, websocket_queue):
while True:
time.sleep(waiting_time)
#Check Websocket queue for new messages
message = websocket_queue.get_received_queue()
# If Incoming websocket JSON has SendMessage string in its Action attribute transform it to request_model
if message is not None and send_sms.Action == "SendMessage":
# Transform it to outgoing_sms_model
reset = ModelHelper.to_outgoing_sms_model(message.Data)
# Add To send_queue of sms
sms_queue.add_send_queue(reset)
finally How I initiate them with asyncio and threading.
client = WebSocketClient(websocket_queue, configs)
loop = asyncio.get_event_loop()
connection = loop.run_until_complete(client.connect())
task1 = asyncio.ensure_future(client.receive_message_from_socket(connection))
task2 = asyncio.ensure_future(client.send_heartbeat_to_socket(connection))
task3 = asyncio.ensure_future(client.send_message_to_socket(connection))
listen_websocket_thread = threading.Thread(target=listen_websocket_routine, args=(sms_queue, websocket_queue))
listen_websocket_thread.start()
loop.run_forever()
So my question is, whenever connetion breaks, I need to re establish the connection. But I am not sure where should I do that. Should it be before everytime I try to send message or receive or should I do that in more general approach?
Since update 10.0 you could do it with an async iterator, like this(example from the official doc):
async for websocket in websockets.connect(...):
try:
...
except websockets.ConnectionClosed:
continue

How to store websockets at the server side with aiohttp?

I'm trying to make simple web-chat with rooms using aiohttp. Can you please advise me how to store my websockets connections? Some code below are simplified a bit. I'm getting an EOF error from socket time by time (and I can reproduce it), but i don't know why. So, i got a question, am i do it right? Should i close websockets everytime when i reload or follow to link? If not, so, how i will connect client with my already opened socket? Sorry for my eng ^^ thanks.
app.py
import asyncio
import aiohttp_jinja2
import jinja2
import hashlib
import collections
import os
from aiohttp_session import session_middleware
from aiohttp_session.cookie_storage import EncryptedCookieStorage
from aiohttp import web
from routes import routes
from middlewares import authorize
from motor import motor_asyncio as ma
from settings import *
basedir = os.path.dirname(os.path.realpath(__file__))
photo_dir = os.path.join(basedir, 'static/photo/')
async def on_shutdown(app):
for ws in app['websockets']:
await ws.close(code=1001, mesage='Server shutdown')
middle = [
session_middleware(EncryptedCookieStorage(hashlib.sha256(bytes(SECRET_KEY, 'utf-8')).digest())),
authorize
]
app = web.Application(middlewares=middle)
aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader('templates'))
for route in routes:
app.router.add_route(*route[:3], name=route[3])
app['static_root_url'] = '/static'
app.router.add_static('/static', 'static', name='static')
app.client = ma.AsyncIOMotorClient(MONGO_HOST)
app.db = app.client[MONGO_DB_NAME]
app.on_cleanup.append(on_shutdown)
app['websockets'] = collections.defaultdict(list)
app['online'] = {}
app['photo_dir'] = photo_dir
web.run_app(app)
and websocket handler
class CompanyWebSocket(web.View):
async def get(self):
ws = web.WebSocketResponse()
await ws.prepare(self.request)
session = await get_session(self.request)
self_id = session.get('user')
login = session.get('login')
company_id = self.request.rel_url.query.get('company_id')
message = Message(self.request.app.db)
company = Company(self.request.app.db)
my_companys = await company.get_company_by_user(self_id)
for c in my_companys:
self.request.app['websockets'][str(c['_id'])].append(ws)
async for msg in ws:
if msg.type == WSMsgType.TEXT:
if msg.data == 'close':
await ws.close()
else:
await message.save_for_company({'data': 'data'})
mess = {
'data': 'data'
}
# send mess to users in company
for company_ws in self.request.app['websockets'][company_id]:
await company_ws.send_json(mess)
elif msg.type == WSMsgType.ERROR:
log.debug('ws connection closed with exception %s' % ws.exception())
try:
self.request.app['websockets'][company_id].remove(ws)
except:
pass
for _ws in self.request.app['websockets'][company_id]:
await _ws.send_json({'user': login, 'type': 'left'})
return ws

Sending many requests in one websocket connection without reconnect

My python program work so slow, because make socket reconnect for any request. I want make one connect and send request, with out reconnect
My functions in file send_by_socket.py, some other function and class call send_to_socket for send logmessage. Now it work, but very slow. Reason - make new connect for any message. I want single connection or poll for use it without reconnect. How make it, possibel have good example with sourcecode?
import asyncio
import websockets
from logging import StreamHandler
import json
async def async_send(message):
async with websockets.connect('wss://****.com/chat') as web_socket:
await web_socket.send(message)
class WebSocketHandler(StreamHandler):
def __init__(self):
StreamHandler.__init__(self)
def emit(self, record):
msg = json.dumps({'log': {'message': record.message, 'date': record.asctime, 'level': record.levelname}})
try:
asyncio.get_event_loop().run_until_complete(async_send(msg))
except ConnectionRefusedError:
pass
def send_to_socket(msg_dict):
msg = json.dumps(msg_dict)
try:
asyncio.get_event_loop().run_until_complete(async_send(msg))
except ConnectionRefusedError:
pass
Now program spend about 1 - 1.2 sec for request. I try
con = websockets.connect('wss://****.com/chat')
con.send('some thing')
but have error AttributeError: 'Connect' object has no attribute 'send'
python
import asyncio
import websockets
from logging import StreamHandler
import json
import time
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
#singleton
class SendToWebSocket:
"""
Send message in web-socket, use one connection for sending.
Try make new connection, if old is lost.
"""
__ws = None
__url = "wss://***.com/chat"
def __init__(self):
self.retryTime = 0
self.retryRepeat = 30
self.__create_connect()
#asyncio.coroutine
def __create_connect(self):
if (time.time() - self.retryTime) > self.retryRepeat:
try:
self.__ws = yield from websockets.connect(self.__url)
self.retryTime = 0
except ConnectionRefusedError:
self.retryTime = time.time()
def send(self, message):
t = type(message)
if t is dict:
msg = json.dumps(message)
elif t is str:
msg = message
else:
raise ValueError("Message must be str or dict. Received %s" % type(t))
if self.__ws is not None:
try:
asyncio.get_event_loop().run_until_complete(self.__async_send(msg))
# print('Send normal')
except ConnectionRefusedError:
# print("Can't send")
# try recreate connect
self.__create_connect()
else:
asyncio.get_event_loop().run_until_complete(self.__create_connect())
async def __async_send(self, message):
await self.__ws.send(message)
class WebSocketHandler(StreamHandler):
"""Custom handler for logging library"""
def __init__(self):
StreamHandler.__init__(self)
self.web_socket = SendToWebSocket()
def emit(self, record):
msg = json.dumps({'log': {'message': record.message, 'date': record.asctime, 'level': record.levelname}})
try:
self.web_socket.send(msg)
except ConnectionRefusedError:
pass

Tornado get input from URL request

My program is to get parameter(URL) from web and in my tornado API, i want to accept them into one bye one. Now my code accepts a single tuple. My api want to fetch the 4 parameters(south-lat,south-long,east-lat,east-long) which comes from the web URL request. And i will implement them into get method of Tornado and find them in my database. I want to know how to accept them in tornado in seperately. This is my current working codes.
import socket
import tornado.web
from datetime import datetime
import pymongo
from pymongo import MongoClient
from pprint import pprint
import tornado.httpserver
import tornado.ioloop
import tornado.options
from tornado.options import define,options
#apicall/v1/geoloc.json?geoquery=True&southwest_lat=''&southwest_lng=''&northeast_lat=''&northeast_lng=''
#tornado port
port = 8088
host = "127.0.0.1"
#make a connection with mongodb
#client=MongoClient()
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("hello APIs")
#what this works is here
class VisualizationHandler(tornado.web.RequestHandler):
def get(self,*args):#how to accept the input from map?
self.open_args=args
#self.open_kwargs=kwargs
print(self.open_args)
print(type(self.open_args))
#self.write("Data is at the terminal")
#client = MongoClient("mongodb://localhost:27017")
#db=client.test
#docs=db.neighborhoods.findOne()
#if docs is None:
#print("Not found")
#else:
#print(docs)
#lat=self.get_argument('lat',True)
#long=self.get_argument('long',True)
#self.write(lat)
#self.write(long)
#var neighborhood = db.neighborhoods.findOne( { geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ slong, slat] } } } } )
def main():
application = tornado.web.Application([
(r"/", MainHandler),
(r"/geo/(.*)",VisualizationHandler),
])
try:
sockets = tornado.netutil.bind_sockets(port, address=host)
print("Socket binding successful to {0}:{1}".format(host, port))
except socket.error:
print("Socket binding failed to {0}:{1}".format(host, port))
return
try:
_id = tornado.process.fork_processes(0, max_restarts=3)
print("Process forked : {}".format(_id))
server = tornado.httpserver.HTTPServer(application)
server.add_sockets(sockets)
tornado.ioloop.IOLoop.current().start()
except KeyboardInterrupt: # stop with Ctrl+C from shell
print("Tornado is stopping")
if __name__ == "__main__":
print("Tornado is starting")
main()
get() method's args/kwargs are retrieved from the url (url regex's match groups, to be specific). Of course, you can create something like this to pass arguments to your function:
(r"/geo/(.*)/(.*)", VisualizationHandler)
or
(r"/geo/(?P<south_lat>.*)/(?P<south_long>.*)", VisualizationHandler)
and args/kwargs south_lat and south_long would be passed to your function from a URL like /geo/123/456, but it's inconvenient. I'd advise you to pass your arguments as URL params /geo?south_lat=123&south_long=456 and read them using get_argument().

Resources