Skip to content

Commit

Permalink
timeou_interaction ok
Browse files Browse the repository at this point in the history
  • Loading branch information
manatlan committed May 30, 2024
1 parent 2a4b6ce commit 06fda6f
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 34 deletions.
9 changes: 3 additions & 6 deletions htagweb/fifo.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@
class Fifo:
# FOLDER="./ses"
FOLDER="/tmp"
def __init__(self,uid:str,moduleapp:str,timeout_interaction:int):
def __init__(self,uid:str,moduleapp:str):
self.uid=uid
self.moduleapp=moduleapp
self.timeout_interaction=timeout_interaction # in seconds

self.CLIENT_TO_SERVER_FIFO = f'{Fifo.FOLDER}/{uid}/{moduleapp}/in'
self.SERVER_TO_CLIENT_FIFO = f'{Fifo.FOLDER}/{uid}/{moduleapp}/out'
Expand Down Expand Up @@ -66,9 +65,7 @@ async def com(self,command:str,**args) -> "str|dict": # for client only
await fifo_out.flush()

# Lire la réponse du process serveur
frame = await asyncio.wait_for(fifo_in.readline(), timeout=self.timeout_interaction)
if frame is None:
raise Exception(f"Timeout response (>{self.timeout_interaction})")
frame = await fifo_in.readline()

#print("Client receive:",frame)
c = json.loads(frame.strip())
Expand All @@ -81,7 +78,7 @@ def childs():
fs=i.split("/")
uid = fs[-3]
moduleapp = fs[-2]
yield Fifo(uid,moduleapp,60)
yield Fifo(uid,moduleapp)

def destroy(self):
if os.path.isfile(self.PID_FILE):
Expand Down
9 changes: 5 additions & 4 deletions htagweb/hrclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@

import multiprocessing

def startHrProcess(uid,moduleapp,timeout_inactivity):
def startHrProcess(uid,moduleapp,timeout_interaction,timeout_inactivity):
""" return '' if ok, or the start error """
queue = multiprocessing.Queue()
p=multiprocessing.Process(target=process, args=[queue,uid,moduleapp,timeout_inactivity],kwargs={},daemon=True)
p=multiprocessing.Process(target=process, args=[queue,uid,moduleapp,timeout_interaction,timeout_inactivity],kwargs={},daemon=True)
p.start()
p.join(timeout=0.2)
return p,queue.get()


class HrClient:
def __init__(self,uid:str, moduleapp:str, timeout_interaction:int=60, timeout_inactivity:int=None):
self._fifo=Fifo(uid,moduleapp,timeout_interaction)
self._fifo=Fifo(uid,moduleapp)
self.timeout_interaction=timeout_interaction
self.timeout_inactivity=timeout_inactivity or 0

async def updater(self):
Expand All @@ -50,7 +51,7 @@ async def create(self, js:str, init=None) -> str:
self.log("reuse fifo process")
else:
self.log("start fifo process")
self._process, err = startHrProcess(self._fifo.uid,self._fifo.moduleapp,self.timeout_inactivity)
self._process, err = startHrProcess(self._fifo.uid,self._fifo.moduleapp,self.timeout_interaction,self.timeout_inactivity)
if err:
raise Exception(err)

Expand Down
17 changes: 11 additions & 6 deletions htagweb/hrprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import logging
logger = logging.getLogger(__name__)

async def main(f:Fifo,klass,timeout_inactivity):
async def main(f:Fifo,klass,timeout_interaction,timeout_inactivity):
print("Serveur:",f)

with open(f.PID_FILE,"w+") as fid:
Expand Down Expand Up @@ -92,8 +92,13 @@ async def cmd(cmd,**args) -> str:
return str(sys.hr)
elif cmd=="interact":
log("interact with",args['id'],args['method'])
actions= await sys.hr.interact(args['id'],args['method'],args["args"],args["kargs"],args["event"])

coro=sys.hr.interact(args['id'],args['method'],args["args"],args["kargs"],args["event"])
try:
actions= await asyncio.wait_for(coro, timeout=timeout_interaction)
except asyncio.TimeoutError:
log("timeout interaction > kill")
process_exit()
actions={}
# always save session after interaction # ALWAYS NEEDED ?? (24/5/24)
sys.hr.session._save()

Expand Down Expand Up @@ -155,18 +160,18 @@ def classname(klass:Tag) -> str:
return klass.__module__+":"+klass.__qualname__


def process(q, uid:str,moduleapp:str,timeout_inactivity:int):
def process(q, uid:str,moduleapp:str,timeout_interaction:int,timeout_inactivity:int):
try:
signal.signal(signal.SIGCHLD, signal.SIG_IGN)

klass=moduleapp2class(moduleapp)

f=Fifo(uid,moduleapp,None) #None, coz it's not involved in hrprocess (don't use com itself, only client side)
f=Fifo(uid,moduleapp)
f.createPipes()
q.put("")

try:
asyncio.run( main(f,klass, timeout_inactivity ) )
asyncio.run( main(f,klass, timeout_interaction,timeout_inactivity ) )
except KeyboardInterrupt:
print("\nServeur: Arrêté par l'utilisateur.")
except Exception as e:
Expand Down
4 changes: 2 additions & 2 deletions htagweb/runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ async def on_connect(self, websocket):
uid=websocket.scope["uid"]

# define hrclient for this socket
self.hr=HrClient(uid,fqn,websocket.app.timeout_interaction)
self.hr=HrClient(uid,fqn)

# define parano mode for this socket
self.is_parano="parano" in websocket.query_params.keys()
Expand Down Expand Up @@ -334,7 +334,7 @@ async def HRHttp(self,request) -> PlainTextResponse:
is_parano="parano" in request.query_params.keys()
seed = parano_seed( uid )

hr=HrClient(uid,fqn,self.timeout_interaction)
hr=HrClient(uid,fqn,self.timeout_interaction,self.timeout_inactivity)
data = await request.body()

if is_parano:
Expand Down
80 changes: 64 additions & 16 deletions test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,27 @@
from htagweb.hrclient import HrClient
import re

class Fucked(Tag.body):
class BugInit(Tag.body):
def init(self):
a=42/0

import time

class AppBlockInteraction(Tag.body):
def init(self,tempo):
async def doit(ev):
if tempo==-1:
while 1:
await asyncio.sleep(0.1) # PERMIT THE LOOP to do its job
pass
else:
await asyncio.sleep(tempo)
# time.sleep(tempo)
self <="!!"
self.b=Tag.Button("say hello",_onclick=doit )
self+=self.b


@pytest.mark.asyncio
async def test_process_trouble_bad_moduleapp():
hr=HrClient("u1","crash")
Expand All @@ -26,7 +43,7 @@ async def test_process_trouble_bad_app(): # but existing module

@pytest.mark.asyncio
async def test_process_trouble_App_crash(): # at start
hr=HrClient("u1","test_server.Fucked")
hr=HrClient("u1","test_server.BugInit")
try:
html = await hr.create("//ddd")
assert 'division by zero' in html
Expand Down Expand Up @@ -138,24 +155,55 @@ async def test_ok( ):
# assert ll[0].fqn == "test_hr:App"


# @pytest.mark.asyncio
# async def test_app_block_killed( server ):
# # test that a blocking interaction will be stopped
# # and app killed
@pytest.mark.asyncio
async def test_timeout_interaction0( ):
# test the interaction in 0s, with a timeout_interaction=1s
uid,fqn ="u2","test_server.AppBlockInteraction"
try:
p=HrClient(uid,fqn,timeout_interaction=1)
html=await p.create("//js",init=([0],{}))
assert html.startswith("<!DOCTYPE html><html>")

# uid ="u2"
# fqn="test_hr:AppFuck"
# p=HrClient(uid,fqn,"//",timeout_interaction=2)
# html=await p.start()
# assert html.startswith("<!DOCTYPE html><html>")
id=re.findall( r'id="(\d+)"',html )[-1]
datas={"id":int(id),"method":"__on__","args":["onclick-"+id],"kargs":{},"event":{}}
actions=await p.interact(**datas)
assert "update" in actions
finally:
await HrClient.clean()

# # app is running
# assert fqn in [i.fqn for i in await p.list()]
@pytest.mark.asyncio
async def test_timeout_interaction3( ):
# test the interaction in 3s, with a timeout_interaction=1s
uid,fqn ="u2","test_server.AppBlockInteraction"
try:
p=HrClient(uid,fqn,timeout_interaction=1)
html=await p.create("//js",init=([3],{}))
assert html.startswith("<!DOCTYPE html><html>")

id=re.findall( r'id="(\d+)"',html )[-1]
datas={"id":int(id),"method":"__on__","args":["onclick-"+id],"kargs":{},"event":{}}
actions=await p.interact(**datas)
assert actions=={} # process is killed
finally:
await HrClient.clean()

# await p.interact( oid="ut", method_name="doit", args=[], kargs={}, event={} )

# # app was killed
# assert fqn not in [i.fqn for i in await p.list()]

@pytest.mark.asyncio
async def test_timeout_interaction_long( ):
uid,fqn ="u2","test_server.AppBlockInteraction"
try:
p=HrClient(uid,fqn,timeout_interaction=1)
html=await p.create("//js",init=([-1],{}))
assert html.startswith("<!DOCTYPE html><html>")

id=re.findall( r'id="(\d+)"',html )[-1]
datas={"id":int(id),"method":"__on__","args":["onclick-"+id],"kargs":{},"event":{}}
actions=await p.interact(**datas)
assert actions=={} # process is killed
finally:
await HrClient.clean()



# @pytest.mark.asyncio
Expand Down

0 comments on commit 06fda6f

Please sign in to comment.