Register:
PUBLIC
PROC[
shh: SHHH, -- encrypts connection
oldSmartsID: Thrush.SmartsID,
oldEpoch: Thrush.Epoch,
machine: Lark.Machine, -- machine name for registering Lark --
model: Lark.LarkModel,
authenticated: BOOL←FALSE,
clientInstance: ROPE ]
RETURNS [ smartsID: Thrush.SmartsID←nullID, epoch: Thrush.Epoch←Thrush.epoch ] = {
larkSh: Lark.SHHH;
localSmarts: ThParty.SmartsInterfaceRecord;
info: SmartsInfo;
larkInterface: LarkOpsRpcControl.InterfaceRecord←NIL;
smarts: REF;
fullRname: ROPE = RPC.GetCaller[shh];
partyRname: ROPE ← fullRname;
dbRname: ROPE;
serviceName: ROPE;
partyType: Thrush.PartyType ← $telephone;
s: VoiceUtils.Rspec ← NIL;
nb: Thrush.NB;
credentials: Thrush.Credentials;
netAddress: Thrush.NetAddress = [machine.net, machine.host, Pup.nullSocket];
Develop partyRname: the actual RName to be used to represent this party; and dbRname: the name under which database items are stored in Grapevine. The rName obtained from the conversation handle may have either form initially, since Finches will supply the former and Larks will supply the latter. Also, obtain the name of the service represented by this Rname, if any, from the database.
IF (s←VoiceUtils.RnameToRspec[partyRname])#
NIL
AND VoiceUtils.RnameToRspec[s.simpleName] # NIL THEN partyRname←s.simpleName;
Above converts from, say, Swinehart.pa.lark to Swinehart.pa.
Also, from Swinehart.pa to Swinehart.pa. Strips one registry if there are two or more.
dbRname ← partyRname.Concat[larkRegistry];
serviceName ← NamesGV.GVGetAttribute[dbRname, $service, NIL];
IF serviceName#NIL THEN partyType ← $service;
The LarkSmarts interface definition suggests that a Lark could present enough information during registration to be simply re-validated (kind of like a hand stamp at a dance) without any great effort. That turns out not to be worth it. If a Lark registers when already registered, we get rid of any old information about it first. Don't assume that its type has not changed from $telephone to $service or vice/versa
DeregisterIfRegistered[netAddress, $telephone];
DeregisterIfRegistered[netAddress, $service];
Get encryption taken care of
larkSh ← IF NOT ThNet.pd.encryptionRequested THEN Thrush.unencrypted
ELSE NamesRPC.StartConversation [
caller: myName.instance,
callee: fullRname,
key: serverPassword,
level:
--<<ECB>>--CBCCheck !
RPC.AuthenticateFailed=> {
VoiceUtils.ProblemFR["Can't authenticate %g to %g", $System,
NIL,
rope[myName.instance], rope[fullRname]]; GOTO NotSmart; }];
Make sure we can talk to the Lark
larkInterface ← LarkOpsRpcControl.ImportNewInterface[
interfaceName: [type: "Lark.Lark", instance: clientInstance] !
RPC.ImportFailed=> {
VoiceUtils.ProblemFR["Can't import Lark interface from %g", $System, NIL, rope[clientInstance]]; GOTO NotSmart; }];
localSmarts ← ThSmartsRpcControl.NewInterfaceRecord[];
localSmarts.clientStubProgress ← ThSmartsPrivate.LarkProgress;
localSmarts.clientStubSubstitution ← ThSmartsPrivate.LarkSubstitution;
localSmarts.clientStubReportAction ← ThSmartsPrivate.LarkReportAction;
[nb, credentials] ← ThPartyPrivate.RegisterLocal[
rName: (
SELECT partyType
FROM
$telephone => partyRname,
ENDCASE=> serviceName),
type: partyType,
interfaceRecord: localSmarts,
properties: [role: $voiceTerminal, netAddress: netAddress]
];
IF nb # $success
OR (smartsID𡤌redentials.smartsID) = nullID
THEN {
VoiceUtils.ProblemFR["Can't register Lark: %g, %g",$System,NIL,
rope[fullRname], rope[clientInstance]]; GOTO NotSmart; };
No further bad things are expected to happen.
smarts ← RefID.Unseal[smartsID];
IF smarts=NIL THEN ERROR;
info ←
NEW[SmartsInfoBody← [
smartsID: smartsID,
partyType: partyType,
ParseEvent: ThSmartsPrivate.LarkParseEvent,
NoteNewStateP: ThSmartsPrivate.NoteNewState,
requests: MBQueue.Create[],
larkInfo:
NEW[ThSmartsPrivate.LarkInfoBody ← [
interface: larkInterface,
shh: larkSh,
netAddress: netAddress,
model: model,
textToSpeech: Rope.Equal[serviceName, "Text-to-Speech", FALSE]
]] ]];
info.larkInfo.larkSmartsInfo ← info;
info.larkInfo.scratchEv ← NEW[Lark.CommandEventSequence[15]];
Triples.Make[$SmartsData, smarts, info];
IF partyType # $service
THEN
[--nb--, info.otherSmartsID]←ThSmartsPrivate.RegisterTrunk[ smartsID, info, partyRname ];
VoiceUtils.ReportFR[" (%g = %g)", $Smarts, info, rope[clientInstance], TU.RefAddr[smarts]];
EnableSmartsE[info];
If the phone is on-hook, mark us ready to go, and set up any once-only Lark params.
IF potentialServiceProvider#
NIL
THEN potentialServiceProvider[
credentials, info];
If anyone has registered, call them. They may want to register a service with our party. See LarkSmartsSynthImpl for an (the) example.
EXITS
NotSmart => RETURN;
};
EnableSmarts:
PUBLIC
INTERNAL
PROC[info: SmartsInfo]
RETURNS[enabled:
BOOL] = {
ENABLE UNWIND, ThSmartsPrivate.LarkFailed =>GOTO Failed;
debugging: BOOL;
SELECT info.larkInfo.larkState
FROM
$none, $failed, $recovering => NULL;
ENDCASE=> RETURN[TRUE];
IF ThSmartsPrivate.CheckHookState[info.larkInfo].onHook=FALSE THEN RETURN[FALSE];
IF ThParty.Enable[ smartsID: info.smartsID] # $success
THEN
{
VoiceUtils.Problem["Could not enable", $Smarts, info]; RETURN[FALSE]; };
IF info.otherSmartsID # nullID
AND
ThParty.Enable[ smartsID: info.otherSmartsID] # $success THEN
{ VoiceUtils.Problem["Impossible", $Smarts, info]; ERROR; };
ThSmartsPrivate.EnterLarkState[ info.larkInfo, none ]; -- Clear any previous failure.
ThSmartsPrivate.EnterLarkState[ info.larkInfo, idle ]; -- Reset the Lark
We're debugging if the lark's mode field in the database has the value "D" or "d"
debugging ← Rope.Equal[case:
FALSE, s2: "D",
s1: NamesGV.GVGetAttribute[
VoiceUtils.InstanceFromNetAddress[info.larkInfo.netAddress, larkRegistry], $mode, "O"]];
ThSmartsPrivate.SetupTimeouts[ info.larkInfo, debugging ]; -- Reset the Lark
RETURN[TRUE];
EXITS Failed => RETURN[FALSE];
};
Deregister:
PUBLIC
INTERNAL
PROC[smartsID: SmartsID] = {
smarts: REF ← RefID.Unseal[smartsID];
otherSmartsID: SmartsID ← nullID;
info: SmartsInfo ←
IF smarts=
NIL
THEN
NIL
ELSE NARROW[Triples.Select[$SmartsData, smarts, -- smartsInfo -- ]];
VoiceUtils.ReportFR["Smarts %d (%g) is dead", $Smarts, info,
card[Reseal[smarts]], TU.RefAddr[smarts]];
IF info#
NIL
THEN {
otherSmartsID ← info.otherSmartsID;
IF info.larkInfo#
NIL
THEN {
ThSmartsPrivate.EnterLarkState[ info.larkInfo, failed ]; -- prevent further action.
info.larkInfo.larkSmartsInfo ← NIL;
IF info.larkInfo.larkTrunkSmartsInfo#
NIL
THEN
info.larkInfo.larkTrunkSmartsInfo.larkInfo ← NIL;
info.larkInfo.larkTrunkSmartsInfo ← NIL;
info.larkInfo ← NIL;
};
}
ELSE
VoiceUtils.ProblemFR["Smarts %d (%g) has no SmartsInfo", $System, NIL, card[Reseal[smarts]], TU.RefAddr[smarts]];
IF otherSmartsID # nullID THEN [--nb--]←ThParty.Deregister[smartsID: otherSmartsID];
[--nb--]←ThParty.Deregister[smartsID: smartsID];
IF info#NIL THEN info.requests.Flush[]; -- Abandon progress-notification queue
};