feat(servidor): adiciona SSE, token, E-Stop real e trava de hardware
- comum.py: ler_json (Origin/JSON/tamanho), gravar_atomico e token (CARINHA_TOKEN ou seguranca.json), substituindo 6 copias nos modulos - eventos.py: hub SSE em /eventos com heartbeat e Last-Event-ID; modulos publicam expressao, telemetria, conversa, reacao, ia, motores - /estado agrega o snapshot inicial; /comando unifica gesto/rosto/cor/reacao - /parar-tudo desliga o PCA9685, para reacoes e trava motores ate /rearmar - braco: lease (ttl_ms) e interpolacao com limite de velocidade no servidor - braco e diagnostico nao disputam o PCA9685 (409 para o segundo dono) - fila limitada (20) com validade de 10 s; POST /face usa prefixo "rosto" - /app/config passa a checar Origin e JSON; versao vem de version.json - figurinhas automaticas do Gemini limitadas a 6 por hora - rosto entende a ordem "calma" enviada pelo E-Stop Token so e exigido quando configurado (docs/SEGURANCA.md). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+3
-8
@@ -2,6 +2,7 @@
|
||||
import json,os,re,threading,time
|
||||
from pathlib import Path
|
||||
import gemini
|
||||
from comum import gravar_atomico, ler_json
|
||||
|
||||
class ConfigAPI:
|
||||
def __init__(self,path):
|
||||
@@ -25,9 +26,7 @@ class ConfigAPI:
|
||||
key=d.get('chave') or os.environ.get('GEMINI_API_KEY','')
|
||||
saved=dict(modelo=d['modelo'])
|
||||
if key:saved['chave']=key
|
||||
tmp=self.path.with_suffix('.tmp');fd=os.open(str(tmp),os.O_WRONLY|os.O_CREAT|os.O_TRUNC,0o600)
|
||||
with os.fdopen(fd,'w',encoding='utf-8') as f:json.dump(saved,f)
|
||||
os.chmod(tmp,0o600);tmp.replace(self.path);os.chmod(self.path,0o600)
|
||||
gravar_atomico(self.path,saved,privado=True)
|
||||
gemini.MODELO=d['modelo']
|
||||
if key:os.environ['GEMINI_API_KEY']=key
|
||||
self.ultimo_teste=None
|
||||
@@ -47,11 +46,7 @@ class ConfigAPI:
|
||||
try:
|
||||
if method=='GET' and route.endswith('/status'):result=self.status()
|
||||
elif method=='POST':
|
||||
origin=h.headers.get('Origin')
|
||||
if origin and origin not in ('http://'+h.headers.get('Host',''),'https://'+h.headers.get('Host','')):raise ValueError('Origem inválida')
|
||||
size=int(h.headers.get('Content-Length',0))
|
||||
if not 0<size<=2048 or h.headers.get('Content-Type','').split(';')[0]!='application/json':raise ValueError('Use JSON até 2048 bytes')
|
||||
d=json.loads(h.rfile.read(size))
|
||||
d=ler_json(h,2048)
|
||||
if route.endswith('/salvar'):result=self.salvar(d)
|
||||
elif route.endswith('/testar'):result=self.testar()
|
||||
else:raise ValueError('Rota inválida')
|
||||
|
||||
Reference in New Issue
Block a user