C'est @ seigo2016 de la classe de programmation N lycée 1ère année. Ce sera N High Adcare Day 8. Je me demandais quoi écrire car c'était un bon article, mais comme j'ai beaucoup parlé du projet principal actuel "Itokake Mandala Color Simulator" chez U22 etc., cette fois j'ai beaucoup parlé du récent projet à court terme "PSS ~ Presentation Support". Je parlerai de "System ~".
Je pense que vous faites souvent des présentations en utilisant PowerPoint, Google Slide, etc. lorsque vous dites quelque chose aux gens. LT a également lieu chaque mois dans la classe de programmation N High (ci-après dénommée Prokura). J'ai donc décidé de créer un système pour soutenir la présentation.
C'est la partie qui accepte et enregistre les commentaires. Tout fonctionne sur Docker. La mémoire est de 1 Go, mais cela fonctionne de manière inattendue.
partie | Performance |
---|---|
VPN | Vultr |
CPU | 1C/1T |
Memory | 1024MB |
OS | OS Debian 10 Buster |
Je l'utilise également pour pratiquer Docker et Docker-Compose.
Nom du conteneur | Aperçu |
---|---|
proxy | Nginx Reverse Proxy |
web | Python3.6(Exécuter Python) |
mysql | DB(Enregistrer les informations de connexion) |
J'ai utilisé bcrypt pour hacher le mot de passe et la bibliothèque mysql-connector pour me connecter à mysql. En plus des éléments suivants, SSL et Socket ont été utilisés.
Python3
bcrypt==3.1.7
mysql-connector==2.2.9
pycrypto==2.6.1
PyYAML==5.2
tornado==6.0.3
J'ai utilisé Tkinter comme bibliothèque pour créer l'interface graphique.
Python3
pdf2image==1.10.0
Pillow==6.2.1
progressbar2==3.47.0
PyYAML==5.2
C'est la partie principale de ce projet. Le système lui-même, dans lequel les commentaires circulent en temps réel, a déjà été créé par d'autres étudiants de clubs professionnels. Cependant, il y avait de nombreuses restrictions telles que ne pas pouvoir l'utiliser si les connexions entre les clients étaient séparées, nous avons donc décidé de créer un nouveau système qui améliorait ces parties. ** Ce système n'enfreint pas le brevet du système de commentaire de Dongo car la méthode de montage et les spécifications sont complètement différentes ** Voilà comment cela fonctionne.
En passant, il y a plusieurs personnes autour de moi qui veulent trouver et signaler des vulnérabilités, donc certaines mesures de sécurité sont nécessaires pour éviter qu'elles ne soient incluses dans la présentation réelle.
C'est la partie qui accepte les commentaires. Le flux est le suivant.
server.py
def send_comment(comment):
#Heure actuelle(JST)
dt_now = dt.now(JST)
#Enregistrer dans la base de données
c = database.cursor()
sql = "INSERT INTO comment (text, entertime) values(%s,%s)"
c.execute(sql,
(comment, dt_now,))
database.commit()
#Assigner à une variable partagée entre les 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 = "commentaire"
if re.search(r'\S', comment) and len(comment) < 30:
send_comment(comment)
self.render('index.html', title=title)
else:
message = "Entrer correctement"
self.render('index.html', title=title, message=message)
Ensuite, ce sera la partie qui envoie le commentaire reçu au client (PC présentateur) par communication socket. Le flux est le suivant.
server.py
def connect_socket(): #Communication par socket
print("SocketStart")
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('0.0.0.0', 10023)) #Ouvert sur le 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("Connexion terminée".encode("utf-8"))
flg = True
else:
conn.sendall("Erreur d'authentification".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()
Après la connexion au serveur, l'envoi des informations d'authentification et la connexion, le client (PC présentateur) reçoit le commentaire.
client.py
def rcv_comment():
#Paramètres de communication du socket
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))
#Préparer les informations d'authentification(Le format est l'utilisateur: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)
#Si une erreur d'authentification est renvoyée, terminez le programme
if comment == "Erreur d'authentification":
break
#Sinon, transmettez le commentaire à la partie du dessin
manager.add_text(comment)
except KeyboardInterrupt:
break
Dessinez le commentaire reçu sur la toile de Tkinter.
client.py
class CommentManager: #Gérer les commentaires de dessin
def __init__(self, canvas):
self.canvas_text_list = []
self.canvas = canvas
root.after(1, self.update)
def add_text(self, comment): #Ajouter un commentaire au flux
#La coordonnée X est au bord de l'écran, la coordonnée y est générée aléatoirement
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): #Déplacer vers la gauche
new_list = []
#Déplacez les commentaires dans la liste vers la gauche.(Il semble préférable de tout faire en même temps en utilisant des balises)
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: #Après s'être déplacé vers l'extrémité gauche
self.canvas.delete(canvas_text)
self.canvas_text_list = new_list
root.after(20, self.update)
Puisque la diapositive elle-même est chargée dans le canevas de Tkinter, mettez simplement à jour l'image
client.py
def next(event): #Envoyer la diapositive
global page
if pagemax - 1 > page:
canvas.itemconfig(labelimg, image=img[page])
page += 1
def prev(event): #Reculer la diapositive
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) #Attribuez la clé ici
root.bind("<Key-p>", prev)
root.mainloop()
Il n'est pas implémenté car je suis inquiet de sélectionner celui à utiliser comme dispositif de pointeur. Je l'ajouterai dès sa mise en œuvre. Un smartphone est-il bon après tout?
J'écris du code en colère qui n'est pas du tout emballé ... Les performances ne sont pas bonnes lorsqu'un grand nombre de commentaires affluent. Je pense qu'il serait sage de l'afficher en superposition.
Recommended Posts