declare [P2PClient TwikiStore] = {Module.link ['x-ozlib://keving/net/p2p/P2PKitClient.ozf' 'x-ozlib://keving/net/TwikiStore.ozf']} % %% If OzStore is false then we use the twickicache %% If OzStore is true then we use the OzStore daemon % GetTwikiCacheURL = 'http://renoir.info.ucl.ac.be/twiki/pub/INGI/TwikiCache/' %%OzStoreTicketFile = 'http://localhost/~keving/OzStoreTicket' OzStoreTicketFile = 'http://www.info.ucl.ac.be/~glynn/OzStoreTicket' OzStore = true OzStoreTicket = if OzStore then OzStoreTicket={Pickle.load OzStoreTicketFile} else unit end Network='keving_plab' %%Network='default' Verbose=10 % %% If argument is error then raise it as an exception %% If success then return content % fun {GetS R} thread case R of error(E) then {Value.failed E} [] success(S) then S end end end %% As GetS, but throws away any success value and kills app on exception proc {GetS_ R} thread case R of error(E) then raise E end [] success(...) then skip end end end % %% Retrieve p2p network entry points from Twiki % ClientEntryPoints = {Map if OzStore then {GetS {Send {Connection.take OzStoreTicket} get(Network $)}} else {TwikiStore.get GetTwikiCacheURL Network} end fun {$ _#(_#_#C)} C end} declare % %% Connect to Peer Network % NWHandle = {GetS {P2PClient.makeClient ClientEntryPoints Verbose}} {System.show 'joined network'} {Property.put 'print.width' 1000} {Property.put 'print.depth' 1000} %% %% flash: Changes the node's colour every 2 seconds %% local fun {FlashMaker Env} [System] = {Env resolve_module_list(['System'])} SetColour = {Env resolve_proc('SetColour')} proc {Loop} {SetColour red} {Delay 2*1000} {SetColour blue} {Delay 2*1000} {Loop} end in {System.show 'XXXXXXXXXX Installing Flash XXXXXXXXX'} thread {Loop} end desc(processor: proc {$ _} skip end) end in _ = {GetS {NWHandle installService(maker: FlashMaker handle: $)}} end %% %% node_details sends the node's id and fully qualified domain name to %% the service in the incoming message %% declare local fun {NodeDetailsMaker Env} [OS System P2PKitPeer] = {Env resolve_module_list(['OS' 'System' 'P2PKitPeer'])} NodeId = {Env resolve_constant('NodeId')} SetColour = {Env resolve_proc('SetColour')} in {System.show 'XXXXXXXXXX Installing Node Details Processor XXXXXXXXX'} {SetColour red} %% Message will contain a servicename to send response to desc(processor: proc {$ M} Msg = M.msg Src = Msg.replyto.id AP = Msg.replyto.ap in {System.show 'XXXXXXXXXX Send my Details XXXXXXXXX'} %% Don't worry if message fails _ = {P2PKitPeer.sendPeer Src AP NodeId#{OS.uName}} end) end in Details = {GetS {NWHandle installService(maker: NodeDetailsMaker handle: $)}} end %% Make a port for replies declare ResponseStream ResponseAP = {GetS {NWHandle makeProxy(stream: ResponseStream proxy: $)}} {GetS_ {Details broadcast(message: msg(replyto:ResponseAP))}} for Id#Nm in ResponseStream do {System.show Id#'\t'#Nm} end declare Snapshot = {NewCell nil} for I in ResponseStream do Snapshot := I|@Snapshot end for Id#Nm in {List.sort @Snapshot fun {$ I#_ J#_} I < J end} do {System.showInfo Id#'\t'#Nm.nodename} end {Browse {Length @Snapshot}} declare fun {DMkr Env} [OS P2PKitPeer] = {Env resolve_module_list(['OS' 'P2PKitPeer'])} NodeId = {Env resolve_constant('NodeId')} in desc(processor: proc {$ M} Msg = M.msg Src = Msg.replyto.id AP = Msg.replyto.ap in %% Don't worry if message fails _ = {P2PKitPeer.sendPeer Src AP NodeId#{OS.uName}} end) end Details = {GetS {NWHandle installService(maker: DMkr handle: $)}} {Inspect {GetS {Details hash(value:kevin message:null rpc: true) $}}} %% Flip Colour declare fun {FlipMkr Env} [SetColour GetColour] = {Env resolve_proc_list(['SetColour' 'GetColour'])} [System] = {Env resolve_module_list(['System'])} {System.show 'XXXXXXXXXX Installing Flip XXXXXXXXX'} in desc(processor: proc {$ _} OldC = {GetColour} NewC = if OldC == 'blue' then 'red' else 'blue' end in {System.showInfo 'XXXXXXXXXX Flip '#OldC#' To '#NewC#' XXXXXXXXX'} {SetColour NewC} end) end Flipper = {GetS {NWHandle installService(name: flip maker: FlipMkr handle: $)}} {GetS_ {Flipper broadcast(message:null)}} %% Replies to any message with pong! declare fun {PingMkr Env} [P2PKitPeer] = {Env resolve_module_list(['P2PKitPeer'])} in desc(processor: proc {$ M} Msg = M.msg Src = Msg.replyto.id AP = Msg.replyto.ap in %% Don't worry if message fails _ = {P2PKitPeer.sendPeer Src AP pong} end) end Pinger = {GetS {NWHandle installService(name: ping maker: PingMkr handle: $)}} %% Swallows all messages declare fun {SwallowMkr _} desc(processor: proc {$ _} skip end) end Swallow = {GetS {NWHandle installService(name: swallow maker: SwallowMkr handle: $)}} %% All nodes ping all other nodes declare fun {BCastPingMkr Env} [P2PKitPeer] = {Env resolve_module_list(['P2PKitPeer'])} NodeId = {Env resolve_constant('NodeId')} SetColour = {Env resolve_proc('SetColour')} in desc(processor: proc {$ _} {SetColour red} %% Don't worry if message fails _ = {P2PKitPeer.broadcast ping o(replyto:o(id:NodeId ap:swallow))} end) end BCastPing = {GetS {NWHandle installService(maker: BCastPingMkr handle: $)}} {GetS_ {BCastPing broadcast(message: fred)}} %% %% Pass a message through a chain of nodes. %% declare local fun {ChainMaker Env} [OS System P2PKitPeer] = {Env resolve_module_list(['OS' 'System' 'P2PKitPeer'])} NodeId = {Env resolve_constant('NodeId')} MyAp = {Env get_ap_name} SetColour = {Env resolve_proc('SetColour')} in {System.show 'XXXXXXXXXX Installing Chain Processor XXXXXXXXX'} %% Message will contain a servicename to send response to desc(processor: proc {$ M} message(chain: Rest colour: NewColour endmsg: EndMsg replyto: EndAP) = M.msg in {System.show 'XXXXXXXXXX Chain XXXXXXXXX'} {SetColour NewColour} case Rest of nil then Src = EndAP.id AP = EndAP.ap in _ = {P2PKitPeer.sendPeer Src AP EndMsg} [] I | Is then _ = {P2PKitPeer.sendKey I MyAp message(chain: Is colour: NewColour endmsg: EndMsg replyto: EndAP)} end end) end in Chain = {GetS {NWHandle installService(maker: ChainMaker handle: $)}} end %% Make a port for replies declare ResponseStream ResponseAP = {GetS {NWHandle makeProxy(stream: ResponseStream proxy: $)}} MyNode = {NWHandle getPeerId($)} {GetS_ {Chain peer(id: MyNode message: message(chain: [751 1886] colour: red endmsg: done replyto: ResponseAP))}} {ForAll ResponseStream System.show} {Browse ResponseStream} %% count number of nodes in a network by passing a token through %% the successor chain declare local fun {CountMaker Env} [OS System P2PKitPeer OP2PS] = {Env resolve_module_list(['OS' 'System' 'P2PKitPeer' 'OP2PS'])} NodeId = {Env resolve_constant('NodeId')} [SetColour GetColour] = {Env resolve_proc_list(['SetColour' 'GetColour'])} CountService = {Env get_ap_name} MaxNetSize = {OP2PS getNetConfig($)}.maxNetSize in {System.show 'XXXXXXXXXX Installing Count Nodes Processor XXXXXXXXX'} {SetColour green} %% Message will contain a servicename to send response to desc(processor: proc {$ M} Msg = M.msg in {SetColour Msg.colour} %% {Delay 2000} {System.show 'XXXXXXXXXX Add to counter and pass it on XXXXXXXXX'#{GetColour}} case Msg of %% Got back home counter(startId: Src counter: N replyto: Reply colour:C) andthen N > 0 andthen Src == NodeId then _ = {P2PKitPeer.sendPeer Reply.id Reply.ap result(N)} [] counter(startId: Src counter: N replyto: Reply colour:C) then SuccId = {OP2PS getSucc($)} HomeDist = if Src-NodeId =< 0 then MaxNetSize+(Src-NodeId) else Src-NodeId end SuccDist = if SuccId-NodeId < 0 then MaxNetSize+(SuccId-NodeId) else SuccId-NodeId end in if HomeDist >= SuccDist then %% Send to successor node _ = {P2PKitPeer.sendPeer SuccId CountService counter(startId: Src counter: N+1 replyto: Reply colour:C)} else %% Originating node has disappeared skip end [] _ then %% Unrecognised message skip end end) end in Count = {GetS {NWHandle installService(maker: CountMaker handle: $)}} end %% Make a port for replies declare ResponseStream ResponseAP = {GetS {NWHandle makeProxy(stream: ResponseStream proxy: $)}} MyPeerId = {NWHandle getPeerId($)} {GetS_ {Count peer(id: MyPeerId message: counter(startId: MyPeerId counter: 0 replyto:ResponseAP colour:red))}} for result(N) in ResponseStream do {System.showInfo "There are "#N#" nodes in the network"} end {Browse ResponseAP} %% gui_details sends the node's id and fully qualified domain name to %% the service in the incoming message %% declare local fun {GuiDetailsMaker Env} [OS System P2PKitPeer OP2PS Record] = {Env resolve_module_list(['OS' 'System' 'P2PKitPeer' 'OP2PS' 'Record'])} [NodeId] = {Env resolve_constant_list(['NodeId'])} [GetColour AddNotification] = {Env resolve_proc_list(['GetColour' 'AddNotification'])} in {System.show 'XXXXXXXXXX Installing Node Details Processor XXXXXXXXX'} %% Message will contain a servicename to send response to desc(processor: proc {$ M} Msg = M.msg Src = Msg.replyto.id AP = Msg.replyto.ap LAP = {OP2PS getLocalAP($)} in {System.show 'XXXXXXXXXX Send my Details XXXXXXXXX'} {AddNotification shutdown Src AP} {AddNotification newcolour Src AP} _ = {P2PKitPeer.sendPeer Src AP details(id:NodeId uname:{String.toAtom {OS.uName}.nodename} fingertable: {Record.filter {OP2PS getFT($)} fun {$ V} V \= unit end} pred: {OP2PS getPred($)} succ: {OP2PS getSucc($)} colour : {GetColour} messageStats: {OP2PS getStatistics($)} ap: ap(ip: {String.toAtom LAP.ip} pn: LAP.pn) )} end) end in Details = {GetS {NWHandle installService(name: gui_details maker: GuiDetailsMaker handle: $)}} end %% Make a port for replies declare ResponseStream ResponseAP = {GetS {NWHandle makeProxy(stream: ResponseStream proxy: $)}} {GetS_ {Details broadcast(message: msg(replyto:ResponseAP))}} {ForAll ResponseStream System.show} {System.showInfo 'Node\tPred\tSucc\tName'} for M in ResponseStream do case M of details(id: Id pred: P succ: S uname: Nm ...) then {System.showInfo Id#'\t'#P#'\t'#S#'\t'#Nm} [] notify(id:Id msg:newcolour(C)) then {System.showInfo Id#' is now '#C} end end %% Count number of requests received declare local fun {CountPingsMaker Env} [System P2PKitPeer] = {Env resolve_module_list(['System' 'P2PKitPeer'])} NodeId = {Env resolve_constant('NodeId')} {System.showInfo 'XXXXXXXXXX Installing Ping Counter XXXXXXXXX'} in desc(initialState: 0 processor: fun {$ M Count} Msg = M.msg Src = Msg.replyto.id AP = Msg.replyto.ap in {System.showInfo 'XXXXXXXXXX Ping '#Count#' XXXXXXXXX'} _ = {P2PKitPeer.sendPeer Src AP NodeId#Count+1} Count+1 end) end in CountPingsFixed = {GetS {NWHandle installService(name: count_pings maker: CountPingsMaker upgradeable: false handle: $)}} end %% Make a port for replies declare ResponseStream ResponseAP = {GetS {NWHandle makeProxy(stream: ResponseStream proxy: $)}} {GetS_ {CountPingsFixed broadcast(message: msg(replyto:ResponseAP))}} {FoldL ResponseStream fun {$ Line Id#Count } {System.showInfo Line#'\t'#Count#'\t'#Id} Line+1 end 1 _} %% Count number of requests received (mutable) declare local fun {CountPingsMaker Env} [System P2PKitPeer] = {Env resolve_module_list(['System' 'P2PKitPeer'])} NodeId = {Env resolve_constant('NodeId')} {System.showInfo 'XXXXXXXXXX Installing Ping Counter XXXXXXXXX'} in desc(initialState: 0 processor: fun {$ M Count} Msg = M.msg Src = Msg.replyto.id AP = Msg.replyto.ap NewCount = Count+5 in {System.showInfo 'XXXXXXXXXX Ping '#Count#' XXXXXXXXX'} _ = {P2PKitPeer.sendPeer Src AP NodeId#NewCount} NewCount end) end in CountPingsMutable = {GetS {NWHandle installService(name: count_pings_m maker: CountPingsMaker upgradeable: true handle: $)}} end %% Make a port for replies declare ResponseStream ResponseAP = {GetS {NWHandle makeProxy(stream: ResponseStream proxy: $)}} {GetS_ {CountPingsMutable broadcast(message: msg(replyto:ResponseAP))}} {FoldL ResponseStream fun {$ Line Id#Count } {System.showInfo Line#'\t'#Count#'\t'#Id} Line+1 end 1 _} declare BadClient = {GetS {NWHandle clientOfService(name: xxx handle: $)}} {GetS_ {BadClient broadcast(message: msg)}} declare PingClient = {GetS {NWHandle clientOfService(name: ping handle: $)}} {Browse {GetS {PingClient key(key: 0 message: msg rpc: true)}}}