.TH SPREE 2.SH NAMESpree \- distributed interactive sessions..SH SYNOPSIS.EX.ps -1.vs -1include "sys.m";include "draw.m";include "sets.m";include "spree.m";spree := load Spree Spree->PATH;Range, Object, Clique, Member: import spree;Set: import Sets;Archive: import Archives; Range: adt { start: int; end: int;}; Object: adt { transfer: fn(o: self ref Object, r: Range, dst: ref Object, i: int); setvisibility: fn(o: self ref Object, visibility: Set); setattrvisibility: fn(o: self ref Object, name: string, visibility: Set); setattr: fn(o: self ref Object, name: string, val: string, vis: Set); getattr: fn(o: self ref Object, name: string): string; delete: fn(o: self ref Object); deletechildren: fn(o: self ref Object, r: Range); id: int; parentid: int; children: array of ref Object; objtype: string; visibility: Set; # ...private data}; Clique: adt { new: fn(parent: self ref Clique, archive: ref Archive, owner: string): (int, string, string); newobject: fn(clique: self ref Clique, parent: ref Object, visibility: int, objtype: string): ref Object; action: fn(clique: self ref Clique, cmd: string, objs: list of int, rest: string, whoto: int); member: fn(clique: self ref Clique, id: int): ref Member; start: fn(clique: self ref Clique); breakmsg: fn(clique: self ref Clique, whoto: Sets->Set); members: fn(clique: self ref Clique): list of ref Member; owner: fn(clique: self ref Clique): string; hangup: fn(clique: self ref Clique); notify: fn(clique: self ref Clique, cliqueid: int, msg: string); objects: array of ref Object; cliqueid: int; # ...private data}; Member: adt { obj: fn(m: self ref Member, id: int): ref Object; del: fn(m: self ref Member, suspend: int); id: int; name: string; # ...private data}; Engine: module { init: fn(srvmod: Spree, clique: ref Clique, argv: list of string): string; command: fn(member: ref Member, e: string): string; join: fn(member: ref Member , e: string, suspended: int): string; leave: fn(member: ref Member): int; notify: fn(fromid: int, s: string); readfile: fn(f: int, offset: big, count: int): array of byte;}; Archives: module { Archive: adt { argv: list of string; # how to restart the session. members: array of string; # members involved. info: list of (string, string); # any other information. objects: array of ref Object; }; init: fn(mod: Spree); write: fn(clique: ref Clique, info: list of (string, string), file: string, members: Set): string; read: fn(file: string): (ref Archive, string); readheader: fn(file: string): (ref Archive, string);}; rand: fn(n: int): int;.ps +1.vs +1.EE.SH DESCRIPTION.I Spreeprovides a general server interface that allows sets of distributedclients,.IR cliques ,to interact in a controlled manner, with theinteraction mediatedby Limbo modules, known as.IR engines .Each engine decides on the rulesof its particular clique; the engine interface is describedat the end of this manual page, under``Module Interface''..PPThis manual page describes theinterface as presented to an engineonce it has been loaded by.IR spree .A loaded instance of an engine is responsible for a particular.IR clique ,in which one or more.I membersparticipate. Messages sent by membersare interpreted by the engine, whichresponds by making changes to the hierarchical.I objectdatabase held by the clique.Behind the scenes.I spreedistributes updates to this database to membersof the clique as appropriate (see.IR spree (4)for details)..SS "Objects and visibility"Objects hold a clique's visible state. An objecthas a unique integer.IR id ,which is an index into the array.IB clique .objects\fR;\fPit also holds a set of attribute-value pairs, a type, andzero or more child objects. Together, all the objectsin the clique form a hierarchical tree, rooted atthe.IR "root object"(id 0), which always exists.Each attribute and each object also has an associated.IR "visibility set" ,the set of member that sees updates to the attributes or the childrenof the object. Each member has a unique id;in a visibility set (see.IR sets (2)),a member is ``visible'' if the set contains the member's id..PPNote that the visibility set of an object does not alter the visibilityof that object's attributes, but only that of its children (and oftheir children: in general an object is visible to a member if theintersection of all its ancestors' visibility sets contains thatmember)..PPObjects can be transferred inside the hierarchy from one parent toanother. If an object is moved to a parent whose visibility conceals itfrom a member, then it will appear to that member to have been deleted;if it is later made visible, then it will be recreated for thatmember.A clique engine can almost always ignore this technicality,except for one thing: the identifier used by a particular member toidentify an object is not necessarily the same as that used by the cliqueengine. Thus when an engine receives an object id in a member'smessage, it should convert it using the.IB member .obj()function..SS \fBClique\fPThe.B Cliquetype holds all the objects in a clique. It allows thecreation of new objects, and provides a way of communicatingwith members directly.All data members of a.B Cliqueshould be treated as read-only..TP 10.IB clique .objectsThis array holds the objects in the clique. An object withidentifier.I idis found at.IB clique .objects[ id ]\fR.\fP.TP.IB clique .new(\fIarchive\fP, \fIowner\fP).B Newcreates a new clique..I Archiveis an archive of the game to be created;.IB archive \.argvshould be non-nil; its first element should namethe engine to be loaded (as a path relative to theengine module directory, and without the.B .disextension)..TP.IB clique .newobject(\fIparent\fP,\ \fIvisibility\fP,\ \fIobjtype\fP).B Newobjectcreates a new object at the endof.IR parent 'schildren;If.I parentis nil, the new object is created under the root object.The new object has visibility.IR visibility ,and type.IR objtype .An object's type cannot be changed onceit has been created..TP.IB clique .action(\fIcmd\fP,\ \fIobjs\fP,\ \fIrest\fP,\ \fIwhoto\fP).B Actionsends a message to some members without affectingthe object hierarchy. It can be used to send transientevents that have no meaning when stored statically(for example, network latency probes).The message is sent to the set of members given by.IR whoto ..I Objsis assumed to be a list of object ids, which areconverted appropriately for each memberreceiving the message; the finalmessage is a string built by concatenating.IR cmd ,the list of object ids, and.IR rest ,separated by spaces..TP.IB clique .breakmsg(\fIwhoto\fP)Messages are usually sent to clients in an uninterruptedstream (as documented in.IR spree (4)),with a single read returning a potentially largeset of messages..B Breakmsgarranges that subsequent messages received by the members specified in.I whotowill see not be merged with messages sent prior to the call to.BR breakmsg .This is used to enable a new client module to be startedwithout needing to pass it data received in the previous read..TP.IB clique .member(\fIid\fP).B Memberyields the member corresponding to identifier.IR id ,or.B nilif there is none..TP.IB clique .membernamed(\fIname\fP).B Membernamedsearches for a member of.I cliquenamed.I nameand returns it if it finds it, otherwise.BR nil ..TP.IB clique .members().B Membersreturns a list of all the members of.IR clique ,including those that have been suspended..TP .IB clique .owner().B Ownerreturns the name of the owner of the clique;i.e. the user that created it..TP.IB clique .hangup().B Hangupterminates a game and informs all theplayers of that fact..TP.IB clique .notify(\fIcliqueid\fP, \fImsg\fP).B Notifysends an informational message to another clique.The clique so referenced must be either the parentor a child of.IR clique .The message is not sent synchronously,and care should be taken not to send messages thatcan cause an indefinite recursion..SS MemberThe.B Membertype represents a member of a clique..TP 10.IB member .idThe member's identifier is an integer unique across all current membersof the clique,but ids of members that have left the clique willbe reused.There may not be two members of the same name in thesame clique..TP.IB member .name.B Nameholds the authenticated name of the member.This is necessarily unique over the membersof a clique..TP.IB member .obj(\fIid\fP).B Objconverts from a member's external objectidentifier to the clique's local.B Objectthat it represents. It returns.B nilif there is no such object..TP.IB member .del(\fIsuspend\fP).B Deldeletes.I memberfrom the clique;no more requests from.I memberwill be received by the clique engine.If.I suspendis non-zero, if a member of the same name joins againit will be allocated the same object id, allowing a memberto leave and join again without losing state..SS \fBObject\fPThe.B Objecttype is the basic unit of clique engine state.An object's children can be selectively concealedfrom members; it holds a set of.RI ( attribute ,\ value )pairs, each of which can be concealed likewise.Where an argument.IR r ,of.B Rangetype is used, it refers to a range of an object'schildren starting at index.IB r .start\fR,\fPand finishing at.IB r .end-1\fR.\fPAll the data members of an.B Objectshould be treated as read-only..TP 10.IB obj .setattr(\fIname\fP,\ \fIval\fP,\ \fIvis\fP).B Setattrsets attribute.I namein.I objto.IR val.If the attribute is being created for thefirst time, then it will be given visibility.IR vis ..I Nameshould be non-empty, and should notcontain any space characters.Note that it is not possible for an attributeto refer directly to an object by its identifier;if this facility is needed, another identifyingscheme should be used. This also appliesto member identifiers, which will changeif the clique is saved and loaded again..TP.IB obj .getattr(\fIname\fP).B Getattryields the current value of theattribute.I namein.IR obj .If an attribute is not set, it yields.BR nil ..TP.IB obj .delete().B Deleteremoves.I objfrom the objecthierarchy..TP.IB obj .deletechildren(\fIr\fP).B Deletechildrendeletes children in range.I rfrom.IR obj ..TP.IB obj .transfer(\fIr\fP,\ \fIdst\fP,\ \fIi\fP).B Transfertransfers the children in range.I rfrom.I objto just before the object at index.I iin.IR dst .It is permissible for.I objand.I dstto be the same object..TP.IB obj .setvisibility(\fIvisibility\fP).B Setvisibilityallows the set of membersgiven in.I visibilityto see the children of.IR obj ,and denies access to all others.Members are notified of the change..TP.IB obj .setattrvisibility(\fIname\fP,\ \fIvisibility\fP).B Setattrvisibilityallows the set of membersgiven in.I visibilityto see the value of.IR obj 'sattribute.IR name ,and denies access to all others.Members are not notified of the change;if there is a need to communicatethe fact of an attribute becoming invisible tomembers, it should be done by using another(visible) attribute to communicate the change..SS "Archives"The.B Archivesmodule provides a means of committing a cliqueto permanent storage and retrieving it later.It should first be initialised by calling.BR init ,passing the.B Spreemodule in.IR mod ..B Writewrites.I cliqueto the file.IR file ..I Infogives a set of attributes and values associated with the clique;.I membersgives the set of clique members for which visibility informationwill be archived; visibility information for other members is forgotten..PP.B Readopens.I fileand returns it as an.B Archiveadt, say.IR a ..IB A .argvholds the command line arguments to the clique module(including the name of the module, its first element);.IB a .membersgives the names of all archived members - the idof an archived member is given by its index in the array;.IB a .infogives the list of attributes an values as stored by.BR write ;.IB a .objectsholds the clique objects..B Readheaderis just like.B readexcept that it parses the header only, so will return an.B Archiveadt such that.IB a .objectsis nil..SS "Module Interface"An engine module,.IR mod ,must implement thefollowing functions. Where a function returns a string,it is interpreted as an error response to the memberresponsible for the request; an empty string signifiesno error..TP.IB mod ->init(\fIsrvmod\fP, \fIclique\fP, \fIargv\fP).B Initinitialises the clique engine..I Cliqueis the clique that the engine is controlling,and.I srvmodis theLines 1–500 of 604. Load more
.TH SPREE 2 .SH NAME Spree \- distributed interactive sessions. .SH SYNOPSIS .EX .ps -1 .vs -1 include "sys.m"; include "draw.m"; include "sets.m"; include "spree.m"; spree := load Spree Spree->PATH; Range, Object, Clique, Member: import spree; Set: import Sets; Archive: import Archives; Range: adt { start: int; end: int; }; Object: adt { transfer: fn(o: self ref Object, r: Range, dst: ref Object, i: int); setvisibility: fn(o: self ref Object, visibility: Set); setattrvisibility: fn(o: self ref Object, name: string, visibility: Set); setattr: fn(o: self ref Object, name: string, val: string, vis: Set); getattr: fn(o: self ref Object, name: string): string; delete: fn(o: self ref Object); deletechildren: fn(o: self ref Object, r: Range); id: int; parentid: int; children: array of ref Object; objtype: string; visibility: Set; # ...private data }; Clique: adt { new: fn(parent: self ref Clique, archive: ref Archive, owner: string): (int, string, string); newobject: fn(clique: self ref Clique, parent: ref Object, visibility: int, objtype: string): ref Object; action: fn(clique: self ref Clique, cmd: string, objs: list of int, rest: string, whoto: int); member: fn(clique: self ref Clique, id: int): ref Member; start: fn(clique: self ref Clique); breakmsg: fn(clique: self ref Clique, whoto: Sets->Set); members: fn(clique: self ref Clique): list of ref Member; owner: fn(clique: self ref Clique): string; hangup: fn(clique: self ref Clique); notify: fn(clique: self ref Clique, cliqueid: int, msg: string); objects: array of ref Object; cliqueid: int; # ...private data }; Member: adt { obj: fn(m: self ref Member, id: int): ref Object; del: fn(m: self ref Member, suspend: int); id: int; name: string; # ...private data }; Engine: module { init: fn(srvmod: Spree, clique: ref Clique, argv: list of string): string; command: fn(member: ref Member, e: string): string; join: fn(member: ref Member , e: string, suspended: int): string; leave: fn(member: ref Member): int; notify: fn(fromid: int, s: string); readfile: fn(f: int, offset: big, count: int): array of byte; }; Archives: module { Archive: adt { argv: list of string; # how to restart the session. members: array of string; # members involved. info: list of (string, string); # any other information. objects: array of ref Object; }; init: fn(mod: Spree); write: fn(clique: ref Clique, info: list of (string, string), file: string, members: Set): string; read: fn(file: string): (ref Archive, string); readheader: fn(file: string): (ref Archive, string); }; rand: fn(n: int): int; .ps +1 .vs +1 .EE .SH DESCRIPTION .I Spree provides a general server interface that allows sets of distributed clients, .IR cliques , to interact in a controlled manner, with the interaction mediated by Limbo modules, known as .IR engines . Each engine decides on the rules of its particular clique; the engine interface is described at the end of this manual page, under ``Module Interface''. .PP This manual page describes the interface as presented to an engine once it has been loaded by .IR spree . A loaded instance of an engine is responsible for a particular .IR clique , in which one or more .I members participate. Messages sent by members are interpreted by the engine, which responds by making changes to the hierarchical .I object database held by the clique. Behind the scenes .I spree distributes updates to this database to members of the clique as appropriate (see .IR spree (4) for details). .SS "Objects and visibility" Objects hold a clique's visible state. An object has a unique integer .IR id , which is an index into the array .IB clique .objects\fR;\fP it also holds a set of attribute-value pairs, a type, and zero or more child objects. Together, all the objects in the clique form a hierarchical tree, rooted at the .IR "root object" (id 0), which always exists. Each attribute and each object also has an associated .IR "visibility set" , the set of member that sees updates to the attributes or the children of the object. Each member has a unique id; in a visibility set (see .IR sets (2)), a member is ``visible'' if the set contains the member's id. .PP Note that the visibility set of an object does not alter the visibility of that object's attributes, but only that of its children (and of their children: in general an object is visible to a member if the intersection of all its ancestors' visibility sets contains that member). .PP Objects can be transferred inside the hierarchy from one parent to another. If an object is moved to a parent whose visibility conceals it from a member, then it will appear to that member to have been deleted; if it is later made visible, then it will be recreated for that member. A clique engine can almost always ignore this technicality, except for one thing: the identifier used by a particular member to identify an object is not necessarily the same as that used by the clique engine. Thus when an engine receives an object id in a member's message, it should convert it using the .IB member .obj() function. .SS \fBClique\fP The .B Clique type holds all the objects in a clique. It allows the creation of new objects, and provides a way of communicating with members directly. All data members of a .B Clique should be treated as read-only. .TP 10 .IB clique .objects This array holds the objects in the clique. An object with identifier .I id is found at .IB clique .objects[ id ]\fR.\fP .TP .IB clique .new(\fIarchive\fP, \fIowner\fP) .B New creates a new clique. .I Archive is an archive of the game to be created; .IB archive \.argv should be non-nil; its first element should name the engine to be loaded (as a path relative to the engine module directory, and without the .B .dis extension). .TP .IB clique .newobject(\fIparent\fP,\ \fIvisibility\fP,\ \fIobjtype\fP) .B Newobject creates a new object at the end of .IR parent 's children; If .I parent is nil, the new object is created under the root object. The new object has visibility .IR visibility , and type .IR objtype . An object's type cannot be changed once it has been created. .TP .IB clique .action(\fIcmd\fP,\ \fIobjs\fP,\ \fIrest\fP,\ \fIwhoto\fP) .B Action sends a message to some members without affecting the object hierarchy. It can be used to send transient events that have no meaning when stored statically (for example, network latency probes). The message is sent to the set of members given by .IR whoto . .I Objs is assumed to be a list of object ids, which are converted appropriately for each member receiving the message; the final message is a string built by concatenating .IR cmd , the list of object ids, and .IR rest , separated by spaces. .TP .IB clique .breakmsg(\fIwhoto\fP) Messages are usually sent to clients in an uninterrupted stream (as documented in .IR spree (4)), with a single read returning a potentially large set of messages. .B Breakmsg arranges that subsequent messages received by the members specified in .I whoto will see not be merged with messages sent prior to the call to .BR breakmsg . This is used to enable a new client module to be started without needing to pass it data received in the previous read. .TP .IB clique .member(\fIid\fP) .B Member yields the member corresponding to identifier .IR id , or .B nil if there is none. .TP .IB clique .membernamed(\fIname\fP) .B Membernamed searches for a member of .I clique named .I name and returns it if it finds it, otherwise .BR nil . .TP .IB clique .members() .B Members returns a list of all the members of .IR clique , including those that have been suspended. .TP .IB clique .owner() .B Owner returns the name of the owner of the clique; i.e. the user that created it. .TP .IB clique .hangup() .B Hangup terminates a game and informs all the players of that fact. .TP .IB clique .notify(\fIcliqueid\fP, \fImsg\fP) .B Notify sends an informational message to another clique. The clique so referenced must be either the parent or a child of .IR clique . The message is not sent synchronously, and care should be taken not to send messages that can cause an indefinite recursion. .SS Member The .B Member type represents a member of a clique. .TP 10 .IB member .id The member's identifier is an integer unique across all current members of the clique, but ids of members that have left the clique will be reused. There may not be two members of the same name in the same clique. .TP .IB member .name .B Name holds the authenticated name of the member. This is necessarily unique over the members of a clique. .TP .IB member .obj(\fIid\fP) .B Obj converts from a member's external object identifier to the clique's local .B Object that it represents. It returns .B nil if there is no such object. .TP .IB member .del(\fIsuspend\fP) .B Del deletes .I member from the clique; no more requests from .I member will be received by the clique engine. If .I suspend is non-zero, if a member of the same name joins again it will be allocated the same object id, allowing a member to leave and join again without losing state. .SS \fBObject\fP The .B Object type is the basic unit of clique engine state. An object's children can be selectively concealed from members; it holds a set of .RI ( attribute ,\ value ) pairs, each of which can be concealed likewise. Where an argument .IR r , of .B Range type is used, it refers to a range of an object's children starting at index .IB r .start\fR,\fP and finishing at .IB r .end-1\fR.\fP All the data members of an .B Object should be treated as read-only. .TP 10 .IB obj .setattr(\fIname\fP,\ \fIval\fP,\ \fIvis\fP) .B Setattr sets attribute .I name in .I obj to .IR val. If the attribute is being created for the first time, then it will be given visibility .IR vis . .I Name should be non-empty, and should not contain any space characters. Note that it is not possible for an attribute to refer directly to an object by its identifier; if this facility is needed, another identifying scheme should be used. This also applies to member identifiers, which will change if the clique is saved and loaded again. .TP .IB obj .getattr(\fIname\fP) .B Getattr yields the current value of the attribute .I name in .IR obj . If an attribute is not set, it yields .BR nil . .TP .IB obj .delete() .B Delete removes .I obj from the object hierarchy. .TP .IB obj .deletechildren(\fIr\fP) .B Deletechildren deletes children in range .I r from .IR obj . .TP .IB obj .transfer(\fIr\fP,\ \fIdst\fP,\ \fIi\fP) .B Transfer transfers the children in range .I r from .I obj to just before the object at index .I i in .IR dst . It is permissible for .I obj and .I dst to be the same object. .TP .IB obj .setvisibility(\fIvisibility\fP) .B Setvisibility allows the set of members given in .I visibility to see the children of .IR obj , and denies access to all others. Members are notified of the change. .TP .IB obj .setattrvisibility(\fIname\fP,\ \fIvisibility\fP) .B Setattrvisibility allows the set of members given in .I visibility to see the value of .IR obj 's attribute .IR name , and denies access to all others. Members are not notified of the change; if there is a need to communicate the fact of an attribute becoming invisible to members, it should be done by using another (visible) attribute to communicate the change. .SS "Archives" The .B Archives module provides a means of committing a clique to permanent storage and retrieving it later. It should first be initialised by calling .BR init , passing the .B Spree module in .IR mod . .B Write writes .I clique to the file .IR file . .I Info gives a set of attributes and values associated with the clique; .I members gives the set of clique members for which visibility information will be archived; visibility information for other members is forgotten. .PP .B Read opens .I file and returns it as an .B Archive adt, say .IR a . .IB A .argv holds the command line arguments to the clique module (including the name of the module, its first element); .IB a .members gives the names of all archived members - the id of an archived member is given by its index in the array; .IB a .info gives the list of attributes an values as stored by .BR write ; .IB a .objects holds the clique objects. .B Readheader is just like .B read except that it parses the header only, so will return an .B Archive adt such that .IB a .objects is nil. .SS "Module Interface" An engine module, .IR mod , must implement the following functions. Where a function returns a string, it is interpreted as an error response to the member responsible for the request; an empty string signifies no error. .TP .IB mod ->init(\fIsrvmod\fP, \fIclique\fP, \fIargv\fP) .B Init initialises the clique engine. .I Clique is the clique that the engine is controlling, and .I srvmod is the