This example extends the functionality of the Socket Demo to
a limited useful application.
A rule is defined with an interpreted method to monitor the addition or removal
of a socket to or from the listener socket This example also demonstrates the overloaded is needed to determine the result type of the enclosing Note how a reference to the newly created proxy object is added to the accepted socket
dynamically. Again, there is no need for a new type or subclass to achieve the desired functionality. Last update: 11 October, 2005connections list. For an addition,
a proxy socket is created to relay any input to and from a remote host. Removal
simply causes the proxy socket to be destroyed - the client property is
removed first for reasons of referential integrity.(.) method of the class
Select for built-in socket properties such as connect,
send, receive and close.
For these, a number of type constraints are needed where the context
is such that a type can't be inferred. For example, the constraintclient.close::Void
if.
-------------------------------------------------------------------------------
--
-- Name: socketProxy.is
--
-------------------------------------------------------------------------------
--
-- Description:
--
-- Demonstration IvoryScript configuration file
--
-- This script defines a simple application to relay and display any
-- input received on a listening socket to a proxy socket.
--
-------------------------------------------------------------------------------
let acceptedSocketRuleMethod rule::Rule event::Expr _::ADS eventPhase::EventPhase =
case event of
{
AddRefEvent client::Socket listener::Socket #connections ->
if listener::Ref = (rule.listenerSocket::Ref) then
let proxy::Socket = .commsStore.Socket[
host: "remotehost", -- To be set appropriately
client: client,
port: 80,
mode: Connect,
onConnected: (\socket::Socket ok::Bool ->
if not ok then {
show "Proxy socket connection failed\n";
(socket.client::Socket).close::Void
}),
onReceive: (\socket::Socket -> let bs::ByteString = socket.receive
in {
show (bytesToString bs);
ignore (((socket.client::Socket).send bs)::Int)
})]
in
if proxy.connect then {
client.proxy := proxy;
client.onReceive :=
(\socket::Socket ->
ignore ((socket.proxy::Socket).send (socket.receive::ByteString))::Int)
} else {
show "Can\'t connect proxy socket\n";
destroyObject proxy;
client.close::Void
};
RemoveRefEvent client::Socket listener::Socket #connections ->
if listener::Ref = (rule.listenerSocket::Ref) and
hasProperty client #proxy then
let proxy::Ref = client.proxy
in {
removeProperty client #proxy;
destroyObject proxy
}
}
in
def {
.socketRule = .Rule [
method: monitorSocket];
.commsStore =.ADS [
ruleList: !RefList[]];
.commsStore.listenerSocket = .commsStore.Socket [
port: 81,
mode: Listener,
onAccept: acceptSocket,
connectionLimit: 2,
connections: !RefList[]];
.acceptedSocketRule = .Rule [
listenerSocket: !.commsStore.listenerSocket,
method: acceptedSocketRuleMethod];
.startADSGroup = !RefList [.commsStore];
.start = mapProcRefs (raiseEvent (StartEvent 0)) (.startADSGroup)
};
addRef (.socketRule) (.commsStore) #ruleList;
addRef (.acceptedSocketRule) (.commsStore) #ruleList;