Client represents a remote sclang application




Client and LocalClient together represent a sender / reciever pair for sclang side osc messages. 

Using SynthDef like global function definitions, ClientFunc, an sclang application 

can evaluate code on a remote sclang app.





Class Methods


*new(name, netAddr) 

returns a new instance and stores it in a global dictionary

the port is set to defaultPort, which is hardcoded presently.

if no address is passed in, localhost is used.



Instance Methods


send(key, args ...)

evaluates a client function that is stored at that key

password_ (symbol)

set the password for interpreter access

cmdName_

set the cmdName under which the client sends (default: '/client')

this cmdName must be the same like the LocalClient reciever cmdName

interpret(string)

if the remote client has the same password, it interprets  the string







LocalClient represents a listener to a remote sclang application

superclass: Client


Note that passing a nil address to LocalClient will make it respond to any remote client 

and try to match any message that is sent from a client object. 

If it is expected to listen to a specific remote client, the address of that client should be used.


Instance Methods

start 

start listening to the world

stop 

stop listening to the world

reply( key, args...)

reply to a sender with a message

 

remove 

remove from client list

isListening 

returns whether it is listening to the world

password_ (symbol)

set the password for interpreter access from outside

cmdName_

set the cmdName under which the client recieves (default: '/client')

this cmdName must be the same like the Client sender cmdName

allowInterpret 

open the interpreter to the world (potential hacking danger)

disallow 

close the interpreter access

ClientFunc similar to SynthDef - represents a client side stored function

*new(name, func)

global function that is accessed by LocalClient when a message is recieved.

the key sent is a key of the ClientFunc that is evaluated.

the other args are passed to the function: time, responder, args...

Note:


for accessing a gui element or a document from an OSCResponder such as the one 

in LocalClient, one has to defer the action:

ClientFunc(\ok, { defer({ ... }) });





// example

// instantiate a remote-local pair (in this case both are local of course)

a = LocalClient.default; // this one listens to any remote client and evaluates the functions. 

b = Client.new; // this one sends the messages


// eqivalent to the above defaults:

a = LocalClient(\default, nil); //addr is nil : listen to all

b = Client(\default, NetAddr("127.0.0.1", 57120));


// store some client functions to be accessible from outside (analogous to SynthDef)

ClientFunc(\ok, { arg ... args; args.postln });

ClientFunc(\yes, { arg ... args; \ok2.postln });


// start the local client

a.start;


// send messages

b.send(\ok, "rrere", 39); 

b.send(\ok, "rrxxxre");

b.send(\ok, 2, 3, 4, 5, 6);

b.send(\yes, "rrere", 39);

b.send(\yes);



opening remote interpreter access is risky, because

anyone can access the interpreter (also unix commands)

if you do not set the password, this is not possible.


// open interpreter

a.password = \xyz;

b.password = \xyz;

a.allowInterpret;


// remote interpret

b.interpret(" Array.fill(8, { [1,0].choose }).postln ");

b.interpret(" String.fill(80, { [$u, $n].choose }).postln");


// remote GUI

b.interpret(" GUI.window.new(\"aLl uR mAchIneZ are bEloNg to us!\").front;{ SinOsc.ar(500, 0, LFPulse.kr(4)) }.play;");  


// close interpret

a.disallow


//test: this should not interpret

b.interpret(" String.fill(8, { [$u, $n].choose }).postln");


a.stop; //stop local responder




writing a chat



(

// hit tab for sending

var n, d, e, b;

n = "John";

d = Document("chat").background_(Color.rand).bounds_(Rect(30, 10, 400, 200));

e = Document("chat-write").background_(Color.rand).bounds_(Rect(30, 210, 400, 50));


a = LocalClient.default.start; 

b = Client.new;

ClientFunc(\chat, { arg str; { d.string =  d.string ++ str ++ "\n" }.defer });


e.keyDownAction_({ arg doc, char;

var string;

if(char === Char.tab) 

{ 

string = n + ":" + e.currentLine;  

b.send(\chat, string.copy); 

AppClock.sched(0.1, { e.string = "" }); // time is the original crime. remove the tab.

} 

});

e.onClose_({ AppClock.sched(0.1, { a.remove; d.close; nil }) }); // sched, otherwise sc crashes

)