Presentation Support System with Python3

Introduction

This is @ seigo2016 for the first year of N High School programming class. It will be N High Advent Day 8. I was wondering what to write because it was a proper article, but since I talked a lot about the current main project "Itokake Mandala Color Simulator" at U22 etc., this time I talked a lot about the recent short-term project "PSS ~ Presentation Support". I will talk about "System ~".

Purpose of PSS ~ Presentation Support System ~

I think that you often give presentations using PowerPoint, Google Slide, etc. when telling something to people. LT is also held every month in the N High Programming Class (hereinafter referred to as Prokura). So I decided to create a system to support the presentation.

function

  1. Comments flow in real time
  2. You can operate the slides from your smartphone, etc.
  3. Pointer can be used (not implemented)

environment

PSS.png

Web server

It is the part that accepts and records comments. Everything runs on Docker. The memory is 1GB, but it works unexpectedly.

Server information

part Performance
VPN Vultr
CPU 1C/1T
Memory 1024MB
OS OS Debian 10 Buster

Docker container information

I also use it to practice Docker and Docker-Compose.

Container name Overview
proxy Nginx Reverse Proxy
web Python3.6(Python execution)
mysql DB(Save login information)

Server environment

I used bcrypt to hash the password and the mysql-connector library to connect to mysql. In addition to the following, SSL and Socket were used.

Python3


bcrypt==3.1.7
mysql-connector==2.2.9
pycrypto==2.6.1
PyYAML==5.2
tornado==6.0.3

Client environment

I used Tkinter as the library for building the GUI.

Python3


pdf2image==1.10.0
Pillow==6.2.1
progressbar2==3.47.0
PyYAML==5.2

Send comments in real time

This is the main part of this project. The system itself, in which comments flow in real time, has already been created by other professional club students. However, there were many restrictions such as not being able to use it if the connections between clients were separated, so we decided to create a new system that improved those parts. ** This system does not infringe the patent of Dongo's comment system because the mounting method and specifications are completely different ** This is how it works.

As an aside, there are several people around me who want to find and report vulnerabilities, so some security measures are needed to prevent them from being dropped into the actual presentation.

server

Web front

This is the part that accepts comments. The flow is as follows.

  1. Verify the received comments for security issues
  2. Record in database if there is a problem
  3. Assign to a variable shared between threads.

server.py


def send_comment(comment):
    #Current time(JST)
    dt_now = dt.now(JST)
    #Record in database
    c = database.cursor()
    sql = "INSERT INTO comment (text, entertime) values(%s,%s)"
    c.execute(sql,
              (comment, dt_now,))
    database.commit()
    #Assign to a variable shared between threads
    with commentbody.get_lock():
        commentbody.value = comment.encode()


class Comment(web.RequestHandler):
    def post(self):
        comment = self.get_argument("comment")
        comment = escape(comment)
        title = "comment"
        if re.search(r'\S', comment) and len(comment) < 30:
            send_comment(comment)
            self.render('index.html', title=title)
        else:
            message = "Input correctly"
            self.render('index.html', title=title, message=message)

Send to client

Next, it will be the part that sends the received comment to the client (presenter PC) by socket communication. The flow is as follows.

  1. Wait for Socket connection on port 10023
  2. Check user information if connected
  3. If the received information matches the user information on the DB, continue the connection.
  4. After that, send the received comment to the client as appropriate. We are checking if the id and password of the sent data match the id and password hash registered in the DB in advance. ~~ ** Isn't the nest deep? ** ~~

server.py


def connect_socket():  #Socket communication
    print("SocketStart")
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.bind(('0.0.0.0', 10023))  #Open on port 10023
        while True:
            s.listen(1)
            print("Waitng ....")
            conn, addr = s.accept()
            flg = False
            while True:
                try:
                    conn = context.wrap_socket(conn, server_side=3)
                    with conn:
                        while True:
                            try:
                                print("Connecting")
                                data = conn.recv(1024).decode()
                                if not data:
                                    break
                                elif ":" in data:
                                    loginuser = data.split(":")[0]
                                    loginpass = data.split(":")[1]
                                    sql = "SELECT id, name, pass FROM users WHERE name = %s"
                                    c.execute(sql, (loginuser,))
                                    userdata = c.fetchall()
                                    if len(userdata) and bcrypt.checkpw(loginpass.encode(), userdata[0][2].encode()):
                                        print("Connected")
                                        conn.sendall("Connection completed".encode("utf-8"))
                                        flg = True
                                    else:
                                        conn.sendall("Authentication error".encode("utf-8"))
                                        conn.close()
                                        flg = False
                                elif flg:
                                    comment = commentbody.value
                                    with commentbody.get_lock():
                                        commentbody.value = "".encode()
                                    if len(comment):
                                        conn.sendall(comment)
                                        comment = ""
                            except socket.error:
                                flg = False
                                break
                except Exception as e:
                    flg = False
                    print("Disconnected\n{}".format(e))
        s.close()

Client (presenter PC)

Receive comments

After connecting to the server, sending the authentication information and logging in, the client (presenter PC) receives the comment.

client.py


def rcv_comment():
    #Socket communication settings
    context = ssl.create_default_context()
    context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
    context.verify_mode = ssl.CERT_NONE
    context.check_hostname = False
    conn = context.wrap_socket(socket.socket(socket.AF_INET),
                               server_hostname=host)
    conn.connect((host, port))
    #Prepare authentication information(The format is user:pass)
    idpass = "{}:{}".format(user_name, user_pass).encode()
    conn.sendall(idpass)
    manager = CommentManager(canvas)
    while True:
        try:
            data = conn.recv(1024)
            if len(data):
                comment = data.decode('utf-8')
                print("recv:" + comment)
                #If an authentication error is returned, complete the program
                if comment == "Authentication error":
                    break
                #Otherwise, pass the comment to the drawing part
                manager.add_text(comment)
        except KeyboardInterrupt:
            break

Comment drawing

Draw the received comment on the Tkinter canvas.

client.py


class CommentManager: #Manage drawing comments
    def __init__(self, canvas):
        self.canvas_text_list = []
        self.canvas = canvas
        root.after(1, self.update)

    def add_text(self, comment): #Add a comment to flow
    #Generate text with x-coordinate at the edge of the screen and y-coordinate at random
        text = self.canvas.create_text(
            w, random.uniform(2.0, 18.0) * 100, text=comment, font=comment_font) 
        self.canvas_text_list.append(text)

    def update(self): #Move to the left
        new_list = []
        #Move comments in the list to the left.(It seems better to do it all at once using tags)
        for canvas_text in self.canvas_text_list: 
            self.canvas.move(canvas_text, -15, 0)
            x, y = self.canvas.coords(canvas_text)
            if x > -10:
                new_list.append(canvas_text)
            else: #After moving to the left end
                self.canvas.delete(canvas_text)
        self.canvas_text_list = new_list
        root.after(20, self.update)

Slide operation

Since the slide itself is loaded into Tkinter's Canvas, just update the image

client.py


def next(event): #Send slides
    global page
    if pagemax - 1 > page:
        canvas.itemconfig(labelimg, image=img[page])
        page += 1


def prev(event): #Move the slide back
    global page
    if 0 <= page:
        canvas.itemconfig(labelimg, image=img[page])
        page -= 1

# ~Omission~ # 
if __name__ == '__main__':
    th = Thread(target=rcv_comment)
    th.setDaemon(True)
    th.start()
    root.bind("<Key-n>", next) #Assign key here
    root.bind("<Key-p>", prev)
    root.mainloop()

Implementation of pointer function

It is not implemented because I am worried about selecting the one to be used as a pointer device. I will add it as soon as it is implemented. Is a smartphone good after all?

Task

--Window adjustment in Mac environment --Verification of security measures --Implementation of pointer function

At the end

I'm writing angry code that isn't packed at all ... Performance is not good when a large number of comments flow. I think it would be wise to display it as an overlay.

Recommended Posts

Presentation Support System with Python3
Make a recommender system with python
System trading starting with Python3: long-term investment
FizzBuzz with Python3
Scraping with Python
Statistics with python
Scraping with Python
Python with Go
"System trade starting with Python3" reading memo
Twilio with Python
Integrate with Python
Play with 2016-Python
AES256 with python
Tested with Python
python starts with ()
with syntax (Python)
Bingo with python
Zundokokiyoshi with python
Excel with Python
Microcomputer with Python
Cast with python
Extract zip with Python (Japanese file name support)
System trading starting with Python 3: Investment and risk
Serial communication with Python
Zip, unzip with python
Django 1.11 started with Python3.6
Primality test with Python
Python with eclipse + PyDev.
Socket communication with Python
Data analysis with python 2
Scraping with Python (preparation)
Try scraping with Python.
Learning Python with ChemTHEATER 03
Sequential search with Python
"Object-oriented" learning with python
Run Python with VBA
Handling yaml with python
Solve AtCoder 167 with python
[Python] Use JSON with Python
Learning Python with ChemTHEATER 05-1
Learn Python with ChemTHEATER
Run prepDE.py with python3
1.1 Getting Started with Python
Collecting tweets with Python
Binarization with OpenCV / Python
3. 3. AI programming with Python
Non-blocking with Python + uWSGI
Scraping with Python + PhantomJS
Posting tweets with python
Drive WebDriver with python
Use mecab with Python3
[Python] Redirect with CGIHTTPServer
Voice analysis with python
Think yaml with python
Operate Kinesis with Python
Getting Started with Python
Use DynamoDB with Python
Handle Excel with python
Ohm's Law with Python
Primality test with python
Run Blender with python