WhiteBoardServer.borg

WhiteBoardServer.borg


{
` client-states,fields and functions
VOTING:1;
JOINED:2;
UNKNOWN:3;
WAITING:4;
_ref:1;
_state:2;
_name:3;
_lasttimer:4;
_continue:5;

clients:[];
mapover(lst,L)::if (!(lst~empty),
    {L(car(lst));
    mapover(cdr(lst),L)});
map(lambda(client))::mapover(clients,lambda);
mapoverstate(state,lambda(client))::
    {pred(client)::if(client[_state]=state,lambda(client));
    mapover(clients,pred)};
newclient(ref)::[ref,UNKNOWN,"",0,void];
getclient(ref)::
    {
    result:void;
    map(if (client[_ref]~ref,result:=client));
    if (is_void(result),clients:=[result:=newclient(ref),clients]);
    result
    };

`mogelijke messages en state-guarding
guard:void;
timerid:1;
join(ref,name)::guard.__join(getclient(ref),name);
mesg(ref,msg)::guard.__mesg(getclient(ref),msg);
okay(ref,id)::guard.__okay(getclient(ref),id);
contwait(ref,cw)::guard.__contwait(getclient(ref),cw);
mesg_timeout(id)::guard.__mesg_timeout(id);
vote_timeout(id)::guard.__vote_timeout(id);

`logging
serverlog(txt)::display(txt+eoln);
clientlog(client,txt)::serverlog(text(client[_ref])+" / "+client[_name]+": "+txt);
ignore(client,txt)::clientlog(client,"ignoring "+txt);

`REPEATING-mode
repeat_queuelast:repeat_queue:[];
repeating_mode()::
    {
    enter()::
        {
        callmsg(cell)::__mesg(cell[1],cell[2]);
        guard:=clone();
        serverlog("---- Repeating Mode ----");
        mapover(repeat_queue,callmsg);
        repeat_queuelast:=repeat_queue:=[]
        };
     __vote_timeout(id)::void;
    __contwait(client,cw)::void;
    __mesg(client,msg)::if (client[_state]=JOINED,
        {
        timerid:=timerid+1;
        mapoverstate(JOINED,
            {clientref:client[_ref];
            clientref->mesg(msg,timerid)});
        starttimer(10,mesg_timeout,timerid);
        clientlog(client,"repeating msg "+text(msg))
        }, ignore(client,"mesg "+text(msg)));
    __join(client,name)::if (client[_state]=UNKNOWN,
        {
        client[_state]:=JOINED;
        client[_name]:=name;
        clientlog(client,"has joined")
        });
    __okay(client,id)::if (client[_state]=JOINED,
        {
        clientlog(client,"said okay");
        client[_lasttimer]:=id
        });
    __mesg_timeout(id)::
        {
        timeouts:false;
        mapoverstate(JOINED,if (client[_lasttimer]clientref:client[_ref];
            clientref->disconnect();
            client[_state]:=WAITING;
            clientlog(client,"disconnected");
            timeouts:=true
            }));
        if (timeouts,voting_mode())
        };
    enter()
    };

`VOTING-mode
` before timeout -- we wait until everybody says continue
` after timeout -- we continue unless somebody said wait
voting_mode()::
    {
    enter()::
        {
        mapoverstate(WAITING,
            mapoverstate(JOINED,
                {voter_ref:client[_ref];
                voter_ref->vote()
                }));
        mapoverstate(JOINED,
            {client[_state]:=VOTING;
            client[_continue]:=void});
        starttimer(10,vote_timeout,timerid:=timerid+1);
        guard:=clone();
        serverlog("---- Voting Mode ----")
        };
    continuecheck()::
        {
        ` check continue without waiting votes
        continuewithoutwait:true;
        mapoverstate(VOTING,if (is_void(client[_continue]),
            continuewithoutwait:=false,
            continuewithoutwait:=continuewithoutwait & client[_continue]));
        ` check whether there are waiting others
        waitingothers:false;
        mapoverstate(WAITING,waitingothers:=true);
        serverlog("continue voted ? ["+text(continuewithoutwait)+"]   waiting others ? ["+text(waitingothers)+"]");
        if ((continuewithoutwait | !waitingothers),
            {
            ` remove voting states and waiting states and back to repeating mode
            mapoverstate(WAITING,client[_state]:=UNKNOWN);
            mapoverstate(VOTING,client[_state]:=JOINED);
            repeating_mode()
            })
        };
    __okay(client,id)::if (client[_state]=JOINED,
        {
        clientlog(client,"said okay");
        client[_lasttimer]:=id
        });
    __contwait(client,cont)::
        {
        if (client[_state]=VOTING,client[_continue]:=cont);
        continuecheck()
        };
    __mesg(client,msg)::if ((client[_state]=JOINED) | (client[_state]=VOTING),
        {
        if (repeat_queuelast~empty, repeat_queue:=repeat_queuelast:=[[client,msg],[]],
            {
            repeat_queuelast[2]:=[[client,msg],[]];
            repeat_queuelast:=repeat_queuelast[2]
            });
        clientlog(client,"queueing message message")
        }, clientlog(client,"not joined or connected, ignoring message"));
    __join(client,name)::
        if (client[_state]=WAITING,
            {
            client[_state]:=JOINED;
            client[_name]:=name;
            clientlog(client,"has reconnected");
            continuecheck()
            },
        if (client[_state]=UNKNOWN,
            {
            client[_state]:=JOINED;
            client[_name]:=name;
            clientlog(client,"has joined")
            }));
    __mesg_timeout(id):serverlog("ignoring old message timout");
    __vote_timeout(id)::if (id=timerid,
        {
        map(if (is_void(client[_continue]),client[_continue]:=true));
        continuecheck()
        });
    enter()
    };

repeating_mode()
}