# Copyright 2007 Kevin Reid, under the terms of the MIT X license # found at http://www.opensource.org/licenses/mit-license.html ................ ? pragma.syntax("0.9") > pragma.enable("accumulator") The hub's job is to manage multiple CapTP connections, creating them on demand and providing them the proper authorities to each other. ? def makeHub :DeepFrozen := # value: The connection maker (which will already have authorities for local garbage collection, swiss table, etc.) receives the information about the connection, the receiver for the remote side, and unique access to its peers. It is used both for incoming and outgoing connections. The connection maker returns three facets: the local receiver (accepting messages from outside), a facet for its peers, and a facet for the next inner layer of the comm system (i.e. LocatorUnum). ? def makeConnection(peerHub, searchPath, vatID, remoteReceiver) { > println(`makeConnection($peerHub, $searchPath, $vatID, $remoteReceiver)`) > var live := true > return [def receiver { > to __printOn(out :TextWriter) { > out.print(`<${live.pick("","dead ")}receiver for $vatID>`) > } > }, > def outwardConnection { > to __printOn(out :TextWriter) { > out.print(`<${live.pick("","dead ")}conn for $vatID>`) > } > to _pingPeer(vID) { return peerHub[["spPing"], vID]._ping() } > to _getPeerHub() { return peerHub } > to _die() { live := false; peerHub.nowDead() } > }, > def peerConnection { > to _ping() { return `pong $vatID` } > }] > }; null The hub's other parameter is the object which initiates connections, yielding remote receivers. XXX terminology is a little confusing; perhaps makeConnection is not a good name for the above? Something more like makeProxyManager? ? def connectOutgoing(localReceiver, searchPath, vatID) { > println(`connectOutgoing($localReceiver, $searchPath, $vatID)`) > when (localReceiver) -> { > println(`local receiver for $vatID: $localReceiver`) > } > return def remoteReceiver { > to __printOn(out :TextWriter) { > out.print(``) > } > } > }; null The hub returns its facet for use by the LocatorUnum. ? def hubOutward := makeHub(makeConnection, connectOutgoing) # value: Making two connections. ? def outc1 := hubOutward[["sp1"], "vi1"] # stdout: connectOutgoing(, ["sp1"], vi1) # makeConnection(, ["sp1"], vi1, ) # # value: ? # stdout: local receiver for vi1: # ? def outc2 := hubOutward[["sp2"], "vi2"] # stdout: connectOutgoing(, ["sp2"], vi2) # makeConnection(, ["sp2"], vi2, ) # # value: ? # stdout: local receiver for vi2: # Accessing an existing connection. (The search path should be ignored.) ? outc1 == hubOutward[["sp1_2"], "vi1"] # value: true Testing access to peer facets. ? outc1._pingPeer("vi2") # value: "pong vi2" Connection death. ? outc2._die() ? def outc2_dead := outc2; null Since the connection for vi2 is dead, another access to it (which we will do through a peer, to test that) starts a new connection. ? outc1._getPeerHub()[["sp2_2"], "vi2"] # stdout: connectOutgoing(, ["sp2_2"], vi2) # makeConnection(, ["sp2_2"], vi2, ) # # value: ? # stdout: local receiver for vi2: # ? def outc2 := hubOutward[["sp2_2"], "vi2"] # value: Checking that the peer facet for the first vi2 connection can't do harm; particularly, that an extra nowDead doesn't delete the old connection: ? outc2_dead._getPeerHub().nowDead() ? outc2 == hubOutward[["sp2_2_2"], "vi2"] # value: true Incoming connections. (XXX should we split this as an inward-facet? little benefit right now, I think) ? def incRec3 := hubOutward.incoming(["sp3"], "vi3", def outRec3 {}) # stdout: makeConnection(, ["sp3"], vi3, ) # # value: ? def outc3 := hubOutward[["sp3_2"], "vi3"] # value: ? outc3._pingPeer("vi1") # value: "pong vi1" 3Desc brand ? def b3 := outc1._getPeerHub().get3DescBrand() # value: CapTP 3Desc transfer ? def s3 := outc1._getPeerHub().get3DescSealer() # value: ? b3 == outc2._getPeerHub().get3DescBrand() # value: true ? s3 == outc2._getPeerHub().get3DescSealer() # value: true ? outc2._getPeerHub().amplifyFor3Desc( > def sampleOther := ( > def handler { to handleOptSealedDispatch(brand) { > if (brand == b3) { > return s3.seal(fn recipID { > println(`recipID = $recipID`) > "descData" })}}}, > Ref.promise()[0], > true), > "foo") # stdout: recipID = foo # # value: "descData" ? outc2._getPeerHub().isOurProxy(sampleOther) # value: true ? outc2._getPeerHub().isOurProxy((def handler { match _ {}}, Ref.promise()[0], true)) # value: false