Giter Site home page Giter Site logo

collabdraw's People

Contributors

anandtrex avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

collabdraw's Issues

Issues with Cairo

Hi anandtrex,

Thanks very much for posting the code to this. I checked out the demo and it looks like a really neat app. I was trying to install this on Ubuntu and ran into an error while following your steps. When I ran ./run_tests.sh I get "ERROR: Failure: ImportError (No module named 'cairo._cairo')" and both tests fail. Do you by chance know how I could fix this? I've tried virtually everything.

Thanks a lot,

Arun

How to manage multiple session whiteboard using tokens ?

I am using your collabdraw application. It is very nice app. I have successfully created the session urls. As shown below,
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":
        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
        page_no = data.get('page', '1')
        token = data.get('token', '')
        find_token = self.redis_client.exists(token)
        if find_token:
            token = ''
        self.init(room_name, page_no, token)

    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):
    if not self.token:
        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)
    else:
        print('fe................##########')
        self.leave_room('token', False)
        self.redis_client.publish(self.construct_key('token', self.token), message)
        self.join_room('token')
        self.application.LISTENERS.setdefault('token', {}).setdefault(self.token, []).append(self)

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):
    if not self.token:
        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 = []
    else:
        self.logger.info("Leaving room %s" % room_name)
        if self in self.application.LISTENERS.get(room_name, {}).get(self.token, []):
            self.application.LISTENERS[room_name][self.token].remove(self)
        if clear_paths:
            self.paths = []

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

def init(self, room_name, page_no, token):
    self.token = token
    if not token:
        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()
            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}))
    else:
        #if 'token' not in self.application.LISTENERS or token not in self.application.LISTENERS['token']:
        #    t = threading.Thread(target=self.redis_listener, args=('token', token))
        #    t.start()
        #    self.application.LISTENER_THREADS.setdefault('token', {}).setdefault(token, []).append(t)
        self.token = token
        self.leave_room('token', False)
        self.join_room('token')
        p = self.redis_client.get(self.construct_key('token', token))
        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': 0}))

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])

But I got the error when draw the whiteboard app. I am using url this way http://localhost:4000/test/ggxeu and error is,

Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python3.2/threading.py", line 740, in _bootstrap_inner
self.run()
File "/usr/lib/python3.2/threading.py", line 693, in run
self._target(_self._args, *_self._kwargs)
File "/home/nyros/Desktop/python3/collabdraw/websockethandler.py", line 43, in redis_listener
listener.send_message(message['data'])
File "/home/nyros/Desktop/python3/collabdraw/websockethandler.py", line 147, in send_message
self.write_message(message)
File "/home/nyros/Desktop/python3/venv3/lib/python3.2/site-packages/tornado/websocket.py", line 165, in write_message
self.ws_connection.write_message(message, binary=binary)
AttributeError: 'NoneType' object has no attribute 'write_message'

Please solve my problem.

Installation fails

When I walk through the instructions, the installation fails at step: pip install -r requirements.txt
I´ve tried this with Ubuntu 16.04 and Debian Jessie.

(venv) root@whiteboard:~/collabdraw# pip install -r requirements.txt
Collecting git+http://anongit.freedesktop.org/git/pycairo (from -r requirements.txt (line 6))
Cloning http://anongit.freedesktop.org/git/pycairo to /tmp/pip-suwlbwj5-build
Collecting decorator==3.4.0 (from -r requirements.txt (line 1))
Downloading decorator-3.4.0.tar.gz
Collecting pystacia==0.1 (from -r requirements.txt (line 2))
Downloading pystacia-0.1.tar.gz
Collecting redis==2.7.2 (from -r requirements.txt (line 3))
Downloading redis-2.7.2.tar.gz (50kB)
100% |################################| 51kB 3.5MB/s
Collecting six==1.2.0 (from -r requirements.txt (line 4))
Downloading six-1.2.0.tar.gz
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "", line 1, in
File "/root/collabdraw/venv/lib/python3.4/site-packages/setuptools/init.py", line 12, in
import setuptools.version
File "/root/collabdraw/venv/lib/python3.4/site-packages/setuptools/version.py", line 1, in
import pkg_resources
File "/root/collabdraw/venv/lib/python3.4/site-packages/pkg_resources/init.py", line 49, in
from six.moves import urllib, map, filter
ImportError: cannot import name 'urllib'

----------------------------------------

Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-ql40ch35/six/
(venv) root@whiteboard:~/collabdraw#

Errors when running main.py

I am trying to install collabdraw and followed the requirements now I am getting this error. Did I miss something?

[collabdraw]# python main.py 
Traceback (most recent call last):
  File "main.py", line 9, in <module>
    from websockethandler import RealtimeHandler
  File "/root/collabdraw/websockethandler.py", line 14, in <module>
    from pystacia import read
  File "/root/virtualenvt/draw/lib/python3.2/site-packages/pystacia/__init__.py", line 155, in <module>
  import pystacia.api.enum as enum_api
  File "/root/virtualenvt/draw/lib/python3.2/site-packages/pystacia/api/enum.py", line 517, in <module>
    from pystacia.util import memoized
  File "/root/virtualenvt/draw/lib/python3.2/site-packages/pystacia/util.py", line 8, in <module>
    from decorator import decorator
  File "/root/virtualenvt/draw/lib/python3.2/site-packages/decorator-3.4.0-py3.2.egg/decorator.py", line 156
    exec code in evaldict
        ^
SyntaxError: invalid syntax

Constant wait screen on first load

Hi. Using both https://collabdraw.herokuapp.com/ and on a local install (Gentoo) give me the same behaviour - the wait spinner onyx-spinner and no response on any interface buttons. Is this application usable at the moment, considering no updates since October?

Just noticed now that the public URL does eventually go past the spinner and show me some quiggles that I presume someone else left there, but application is still nonresposive. Five minutes later local install is still spinning, no output on the console except favicon 404s.

Instructions: how do I "run the redis server"

Following the instructions which currently state:

RUNNING:
-------------
1. Run the redis server
2. Run "python main.py"

How do you run a redis server?

I just tried running "python main.py" and get an error message as follows:
# python main.py
Listening on port 5000
Open connection
INFO:websocket:Open connection
WARNING:tornado.access:404 GET /favicon.ico (192.168.1.100) 0.52ms
WARNING:tornado.access:404 GET /favicon.ico (192.168.1.100) 0.44ms
Processing event init
DEBUG:websocket:Processing event init
Initializing with room name
INFO:websocket:Initializing with room name
Initializing one and 1
INFO:websocket:Initializing one and 1
Starting listener thread for room one
INFO:websocket:Starting listener thread for room one
Leaving room
INFO:websocket:Leaving room
Joining room one
INFO:websocket:Joining room one
ERROR:tornado.application:Uncaught exception in /realtime/
Traceback (most recent call last):
File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 232, in connect
sock = self._connect()
File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 244, in _connect
sock.connect((self.host, self.port))
socket.error: [Errno 111] Connection refused

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib64/python3.2/site-packages/redis/client.py", line 393, in execute_command
    connection.send_command(*args)
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 306, in send_command
    self.send_packed_command(self.pack_command(*args))
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 288, in send_packed_command
    self.connect()
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 235, in connect
    raise ConnectionError(self._error_message(e))
redis.exceptions.ConnectionError: Error 111 connecting localhost:6379. Connection refused.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 232, in connect
    sock = self._connect()
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 244, in _connect
    sock.connect((self.host, self.port))
socket.error: [Errno 111] Connection refused

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib64/python3.2/site-packages/tornado/websocket.py", line 303, in wrapper
    return callback(*args, **kwargs)
  File "/usr/local/src/collabdraw/websockethandler.py", line 68, in on_message
    self.init(room_name, page_no)
  File "/usr/local/src/collabdraw/websockethandler.py", line 149, in init
    n_pages = self.redis_client.get(self.construct_key("info", self.room_name, "npages"))
  File "/usr/lib64/python3.2/site-packages/redis/client.py", line 616, in get
    return self.execute_command('GET', name)
  File "/usr/lib64/python3.2/site-packages/redis/client.py", line 397, in execute_command
    connection.send_command(*args)
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 306, in send_command
    self.send_packed_command(self.pack_command(*args))
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 288, in send_packed_command
    self.connect()
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 235, in connect
    raise ConnectionError(self._error_message(e))
redis.exceptions.ConnectionError: Error 111 connecting localhost:6379. Connection refused.Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 232, in connect
    sock = self._connect()
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 244, in _connect
    sock.connect((self.host, self.port))
socket.error: [Errno 111] Connection refused

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib64/python3.2/site-packages/redis/client.py", line 1643, in execute_command
    connection.send_command(*args)
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 306, in send_command
    self.send_packed_command(self.pack_command(*args))
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 288, in send_packed_command
    self.connect()
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 235, in connect
    raise ConnectionError(self._error_message(e))
redis.exceptions.ConnectionError: Error 111 connecting localhost:6379. Connection refused.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 232, in connect
    sock = self._connect()
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 244, in _connect
    sock.connect((self.host, self.port))
socket.error: [Errno 111] Connection refused

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib64/python3.2/threading.py", line 740, in _bootstrap_inner
    self.run()
  File "/usr/lib64/python3.2/threading.py", line 693, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/src/collabdraw/websockethandler.py", line 38, in redis_listener
    r.subscribe(self.construct_key(room_name, page_no))
  File "/usr/lib64/python3.2/site-packages/redis/client.py", line 1696, in subscribe
    return self.execute_command('SUBSCRIBE', *channels)
  File "/usr/lib64/python3.2/site-packages/redis/client.py", line 1648, in execute_command
    connection.connect()
  File "/usr/lib64/python3.2/site-packages/redis/connection.py", line 235, in connect
    raise ConnectionError(self._error_message(e))
redis.exceptions.ConnectionError: Error 111 connecting localhost:6379. Connection refused.


Leaving room one
INFO:websocket:Leaving room one

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.