Giter Site home page Giter Site logo

Comments (5)

anandtrex avatar anandtrex commented on July 21, 2024

What version of tornado do you have running?
Also can you attach your main.py if you've made any changes to it? It'll help me debug this issue.

from collabdraw.

dhanababu-nyros avatar dhanababu-nyros commented on July 21, 2024

Hi Thanks for reply,
I am using Torndao-3.1. I have changed the two files one is websockethandler.py and another one is main.py.

Please find code here for main.py:

import logging
import uuid

import tornado.httpserver
import tornado.ioloop
import tornado.web
import tornado.template as template

from websockethandler import RealtimeHandler
from uploadhandler import UploadHandler
from loginhandler import LoginHandler
from logouthandler import LogoutHandler
from registerhandler import RegisterHandler
import config

logger = logging.getLogger('websocket')
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)

class IndexHandler(tornado.web.RequestHandler):
def get_current_user(self):
if not config.DEMO_MODE:
return self.get_secure_cookie("loginId")
else:
return True

@tornado.web.authenticated
def get(self):
    #print('...........authenticated.......')
    loader = template.Loader(config.ROOT_DIR)
    return_str = loader.load("index.html").generate(app_ip_address=config.APP_IP_ADDRESS,
                                                    app_port=config.PUBLIC_LISTEN_PORT, token='')
    self.finish(return_str)

class RedirectHandler(tornado.web.RequestHandler):
def get(self, token_id):
loader = template.Loader(config.ROOT_DIR)
return_str = loader.load("index.html").generate(app_ip_address=config.APP_IP_ADDRESS,
app_port=config.PUBLIC_LISTEN_PORT, token=token_id)
self.finish(return_str)

class Application(tornado.web.Application):
def init(self):
handlers = [
(r'/realtime/', RealtimeHandler),
(r'/resource/(.)', tornado.web.StaticFileHandler,
dict(path=config.RESOURCE_DIR)),
(r'/test/resource/(.
)', tornado.web.StaticFileHandler,
dict(path=config.RESOURCE_DIR)),
(r'/upload', UploadHandler),
(r'/login.html', LoginHandler),
(r'/logout.html', LogoutHandler),
(r'/register.html', RegisterHandler),
(r'/index.html', IndexHandler),
(r'/test/(?P<token_id>\w+)', RedirectHandler),
(r'/(.*)', tornado.web.StaticFileHandler,
dict(path=config.ROOT_DIR)),
]

    self.LISTENERS = {}
    self.LISTENER_THREADS = {}

    settings = dict(
        auto_reload = True,
        gzip = True,
        login_url = "login.html",
        cookie_secret = str(uuid.uuid4()),
    )

    tornado.web.Application.__init__(self, handlers, **settings)

if name == "main":
if not config.ENABLE_SSL:
http_server = tornado.httpserver.HTTPServer(Application())
else:
http_server = tornado.httpserver.HTTPServer(Application(), ssl_options={
"certfile": config.SERVER_CERT,
"keyfile": config.SERVER_KEY,
})
logger.info("Listening on port %s" % config.APP_PORT)
http_server.listen(config.APP_PORT)
tornado.ioloop.IOLoop.instance().start()

Here for websockethandler.py:

import logging
import json
import os
import threading
import subprocess
import uuid
from zlib import compress
from urllib.parse import quote
from base64 import b64encode
import tornado.websocket
import tornado.web
import redis
from pystacia import read

from tools import hexColorToRGB, createCairoContext
import config

class RealtimeHandler(tornado.websocket.WebSocketHandler):
room_name = ''
token = ''
paths = []
redis_client = None
page_no = 1
num_pages = 1

def construct_key(self, namespace, key, *keys):
    publish_key = ""
    if len(keys) == 0:
        publish_key = "%s:%s" % (namespace, key)
    else:
        publish_key = "%s:%s:%s" % (namespace, key, ":".join(keys))
    return publish_key

def redis_listener(self, room_name, page_no):
    self.logger.info("Starting listener thread for room %s" % room_name)
    rr = redis.Redis(host=config.REDIS_IP_ADDRESS, port=config.REDIS_PORT, db=1)
    r = rr.pubsub()
    r.subscribe(self.construct_key(room_name, page_no))
    for message in r.listen():
        for listener in self.application.LISTENERS.get(room_name, {}).get(page_no, []):
            self.logger.debug("Sending message to room %s" % room_name)
            listener.send_message(message['data'])

def open(self):
    self.logger = logging.getLogger('websocket')
    self.logger.info("Open connection")
    self.send_message(self.construct_message("ready"))
    self.redis_client = redis.Redis(host=config.REDIS_IP_ADDRESS, db=2)

def on_message(self, message):
    m = json.loads(message)
    event = m.get('event', '').strip()
    data = m.get('data', {})
    self.logger.debug("Processing event %s" % event)
    if not event:
        self.logger.error("No event specified")
        return

    if event == "init":
        token = data.get('token', '')
        find_token = self.redis_client.exists(self.construct_key('token', token))
        print(token, find_token)
        room_name = data.get('room', '')
        page_no = data.get('page', '1')
        if token:
            if not find_token:
                self.send_message(self.construct_message("forword", {}))
            else:
                room_name = 'token'
                self.token = token
                page_no = token
        else:
            self.token = ''
            print('.........................')
            self.logger.info("Initializing with room name %s" % self.room_name)
            room_name = data.get('room', '')
            if not room_name:
                self.logger.error("Room name not provided. Can't initialize")
                return
        self.init(room_name, page_no)

    elif event == "draw-click":
        singlePath = data['singlePath']
        if not self.paths:
            self.logger.debug("None")
            self.paths = []
        self.paths.extend(singlePath)
        self.broadcast_message(self.construct_message("draw", {'singlePath': singlePath}))
        if not self.token:
            self.redis_client.set(self.construct_key(self.room_name, self.page_no), self.paths)
        else:
            self.redis_client.set(self.construct_key('token', self.token), self.paths)

    elif event == "save":
        self.redis_client.set(self.construct_key(self.room_name, self.page_no), self.paths)
        self.init(self.room_name, self.page_no)

    elif event == "savesession":
        token = data['token']
        self.paths = []
        self.redis_client.set(self.construct_key('token', token), self.paths)
        self.send_message(self.construct_message("token", {'token': token}))
        #self.init(self.room_name, self.page_no)

    elif event == "clear":
        self.broadcast_message(self.construct_message("clear"))
        self.redis_client.delete(self.construct_key(self.room_name, self.page_no))

    elif event == "get-image":
        if self.room_name != data['room'] or self.page_no != data['page']:
            self.logger.warning("Room name %s and/or page no. %s doesn't match with current room name %s and/or page no. %s. Ignoring" % (data['room'],
                            data['page'], self.room_name, self.page_no))
        image_url, width, height = self.get_image_data(self.room_name, self.page_no)
        self.send_message(self.construct_message("image", {'url': image_url,
                                                            'width': width, 'height': height}))

    elif event == "video":
        self.make_video(self.room_name, self.page_no)

    elif event == "new-page":
        self.logger.info("num_pages was %d" % self.num_pages)
        self.redis_client.set(self.construct_key("info", self.room_name, "npages"),
                              self.num_pages + 1)
        self.num_pages += 1
        self.logger.info("num_pages is now %d" % self.num_pages)
        self.init(self.room_name, self.num_pages)

def on_close(self):
    self.leave_room(self.room_name)

def construct_message(self, event, data = {}):
    m = json.dumps({"event": event, "data": data})
    return m

def broadcast_message(self, message):
    self.leave_room(self.room_name, False)
    self.redis_client.publish(self.construct_key(self.room_name, self.page_no), message)
    self.join_room(self.room_name)

def send_message(self, message):
    if type(message) == type(b''):
        self.logger.info("Decoding binary string")
        message = message.decode('utf-8')
    elif type(message) != type(''):
        self.logger.info("Converting message from %s to %s" % (type(message),
                                                        type('')))
        message = str(message)
    message = b64encode(compress(bytes(quote(message), 'utf-8'), 9))
    self.write_message(message)

def leave_room(self, room_name, clear_paths = True):

    self.logger.info("Leaving room %s" % room_name)
    if self in self.application.LISTENERS.get(room_name, {}).get(self.page_no, []):
        self.application.LISTENERS[room_name][self.page_no].remove(self)
    if clear_paths:
        self.paths = []

def join_room(self, room_name):
    self.logger.info("Joining room %s" % room_name)
    self.application.LISTENERS.setdefault(room_name, {}).setdefault(self.page_no, []).append(self)

def init(self, room_name, page_no):
    self.logger.info("Initializing %s and %s" % (room_name, page_no))
    if room_name not in self.application.LISTENERS or page_no not in self.application.LISTENERS[room_name]:
        t = threading.Thread(target=self.redis_listener, args=(room_name, page_no))
        t.start()
        print("find ....", t)
        self.application.LISTENER_THREADS.setdefault(room_name, {}).setdefault(page_no, []).append(t)

    self.leave_room(self.room_name)
    self.room_name = room_name
    self.page_no = page_no
    self.join_room(self.room_name)

    n_pages = self.redis_client.get(self.construct_key("info", self.room_name, "npages"))
    if n_pages:
        self.num_pages = int(n_pages.decode('utf-8'))
    # First send the image if it exists
    image_url, width, height = self.get_image_data(self.room_name, self.page_no)
    self.send_message(self.construct_message("image", {'url': image_url,
                                                       'width': width, 'height': height}))
    # Then send the paths
    p = self.redis_client.get(self.construct_key(self.room_name, self.page_no))
    if p:
        self.paths = json.loads(p.decode('utf-8').replace("'", '"'))
    else:
        self.paths = []
        self.logger.info("No data in database")
    self.send_message(self.construct_message("draw-many",
                                             {'datas': self.paths, 'npages': self.num_pages}))

def get_image_data(self, room_name, page_no):
    image_url = "files/" + room_name + "/" + str(page_no) + "_image.png";
    image_path = os.path.realpath(__file__).replace(__file__, '') + image_url
    try:
        image = read(image_path)
    except IOError as e:
        self.logger.error("Error %s while reading image at location %s" % (e, image_path))
        return '', -1, -1
    width, height = image.size
    return image_url, width, height

def make_video(self, room_name, page_no):
    p = self.redis_client.get(self.construct_key(room_name, page_no))
    os.makedirs('tmp', exist_ok=True)
    prefix = 'tmp/'+str(uuid.uuid4())
    if p:
        points = json.loads(p.decode('utf-8').replace("'",'"'))
        i = 0
        c = createCairoContext(920, 550)
        for point in points:
            c.set_line_width(float(point['lineWidth'].replace('px','')))
            c.set_source_rgb(*hexColorToRGB(point['lineColor']))
            if point['type'] == 'dragstart' or point['type'] == 'touchstart':
                c.move_to(point['oldx'], point['oldy'])
            elif point['type'] == 'drag' or point['type'] == 'touchmove':
                c.move_to(point['oldx'], point['oldy'])
                c.line_to(point['x'], point['y'])
            c.stroke()
            f = open(prefix+"_img_"+str(i)+".png", "wb")
            c.get_target().write_to_png(f)
            f.close()
            i += 1
        video_file_name = prefix+'_video.mp4'
        retval = subprocess.call(['ffmpeg', '-f', 'image2', '-i', prefix+'_img_%d.png', video_file_name])
        self.logger.info("Image for room %s and page %s successfully created. File name is %s" % (room_name, page_no, video_file_name))
        if retval == 0:
            # Clean up if successfull
            cleanup_files = prefix+'_img_*'
            self.logger.info("Cleaning up %s" % cleanup_files)
            subprocess.call(['rm', cleanup_files])

May be I think I solved this issue. But few issues are there. When the user first time draws on whiteboard it is not saved into database. I am expecting feedback from you. Thanks.

from collabdraw.

anandtrex avatar anandtrex commented on July 21, 2024

I'm looking into it.

from collabdraw.

dhanababu-nyros avatar dhanababu-nyros commented on July 21, 2024

Ok thanks for your supporting. I am looking forward for your reply.

from collabdraw.

anandtrex avatar anandtrex commented on July 21, 2024

I can't seem to reproduce the issue of the first time drawing not being saved in database. Please open a new issue with more details if you're still seeing the problem.

For the record, can you post your solution to your first problem?

from collabdraw.

Related Issues (8)

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.