| 
 
 | This is an old document
                  describing how users of a ScriptEase Javascript/Ecmascript
                  product, or a product that is created with those libraries,
                  can include Distributed Scripting into their application.
                  Javascript users could use this protocol following the Distributed Scripting Protocol manual. SE:DSP
                  was a technology created by no-longer-existing Nombas. For more documentation, see Old Nombas User Docs. 
 DSP Link LibraryDistributed Scripting Protocol is
                  implemented by the ScriptEase DSP link library as the DSP
                  object. DSP Objectplatform: All platforms except
                  Dos; All versions of SE  source: #link <sedsp> 
 The DSP object provides a
                  framework for implementing distributed scripting across a
                  variety of computers and networks. Creating a DSP objectThe Distributed Scripting Protocol
                  provides no internal method for managing a connection or
                  transporting packets. It is simply a framework, with the
                  physical transport method being supplied by the user. As such,
                  it is impossible to simply create a DSP object, because it is
                  incapable of doing anything by itself. The user must supply a
                  set of functions to manage the connection with the server. To
                  create a DSP object, you call new
                  DSP(myOpenFunction, myParameters). The
                  function that you supply must open the connection and return a
                  reference to it. It is possible in some instances that you do
                  not need to open anything special, and so you can ignore this
                  parameter. Here is an example of an open function for a DSP
                  connection, using internet sockets: function idspOpen( host, port ) {  return new Socket( host, port
                  ); } 
 We will see this function
                  passed to the DSP constructor in a moment. First, to
                  accomplish sending/receiving packets, the user needs to define
                  two functions, dspSend
                  and dspReceive.
                  These functions must be inherited through the prototype chain,
                  because otherwise when DSP objects are copied implicitly
                  through reference construction (see below), the functions will
                  not get passed. Because we want to keep the DSP functions
                  (such as dspService), we need to preserve the original DSP
                  prototype, and a constructor looks like the following: function iDSP( host, port ) {  var ret = new DSP( idspOpen,
                  host, port );  // Now we override the
                  ._prototype to insert our functions  if( ret != null )  ret._prototype =
                  iDSP.prototype;  return ret; } // Here we set up the
                  iDSP.prototype to keep the DSP functions // in the chain iDSP.prototype._prototype =
                  DSP.prototype; 
 Once this constructor is
                  called, we have a valid DSP object, assuming we add the
                  transport functions. To do this, we must add dspSend
                  and dspReceive
                  to the prototype. The actual syntax of these functions is
                  similar to Clib.fread()
                  and Clib.fwrite(),
                  and a description can be found in the function reference. For
                  our iDSP example, they would look something like this: function iDSP.prototype.dspSend(
                  conn, buffer, timeout ) { // Ignore timeout  return conn.write(buffer); } function
                  iDSP.prototype.dspReceive( conn, &buffer, length, timeout) {  return conn.read( buffer,
                  length ); } 
 Note that both these functions
                  ignore the timeout parameter and do not correctly handle
                  errors. A full-featured version of these functions can be
                  found in the file idsp.jsh.
                  The final function that we must provide is the dspCloseConnection
                  function, which is responsible for closing the connection.
                  This function looks like the following: function
                  iDSP.prototype.dspCloseConnection( conn ) {  conn.close(); } 
 Once all of these transport
                  functions have been defined, new iDSP objects can be
                  instantiated with a call to new iDSP
                  and used as any other DSP object. Because the transport level
                  of DSP is separate from the core library, DSP can be adapted
                  to communicate between any servers in any way. In addition,
                  communication can be done during the call to the open
                  function. This allows for password authentication or any other
                  information to be shared. Using a DSP objectOnce a DSP object is created using
                  the method described above, every DSP object behaves in
                  exactly the same way. Once the functions are set up, the
                  transport layer of the protocol is hidden. The basic idea is that all DSP
                  objects are in fact references to objects on the remote side,
                  and they will remain so except under certain circumstances
                  (described below). When a connection is first established, it
                  is a reference to the global object. Members of the remote
                  global object can be accessed as members of the connection.
                  But they remain references, so var
                  print = connection.Clib.printf will
                  not actually make a remote call to the server. At the
                  appropriate time, print
                  will be resolved into Clib.printf()
                  and sent to the server in the appropriate manner. The
                  circumstances which can trigger a de-referencing and remote
                  call are: Calling functions
                  - When a DSP reference is called as a function, it gets
                  resolved into the appropriate path and the function is called
                  on the remote server. All parameters are converted to source
                  with ToSource()
                  and passed to the server, and set back afterwards (in case any
                  were passed by reference). The client waits for the return
                  value from the server and returns that as the result of the
                  function call. This makes calling functions transparent to the
                  client, so connection.Screen.writeln("hi")
                  will actually call Screen.writeln
                  on the server and print out "hi". Setting a value
                  - When a value is put to a DSP reference, such as connection.globalCount
                  = 5, a remote call to the server is
                  generated, and the remote value is updated. The above case
                  acts just as if globalCount = 5
                  was executed on the server. Implicitly
                  - When a DSP reference is converted to a primitive, then it
                  gets de-referenced. This implicit conversion happens mostly in
                  operator expressions, in which both values are converted to
                  primitives first. So var myCount =
                  connection.globalCount + 1 will get
                  the value of globalCount
                  from the server and add one to it. This can also be
                  accomplished explicitly with ToPrimitive(),
                  but the method below is more straightforward and
                  understandable. The explicit use of ToPrimitive() on DSP
                  references is discouraged. Explicitly
                  - Any DSP reference can be explicitly de-referenced with a
                  call to.dspGetValue.
                  Once an object has been de-referenced this way, any subsequent
                  accesses will not cause a remote call, and changes will only
                  affect the local copy. Note that calling a function in this
                  way will result in the function being called on the local
                  client, not the server. DSP object instance methodsDSP() 
                
                  
                    | syntax: | new DSP( [openFunction[,
                          param1[, ...]]]) |  
                    | where: | openFunction - The
                          function to call to initialize the connection. paramN - Additional
                          parameters to pass to the open function |  
                    | return: | object - A new DSP
                          object, or null
                          on error. This is the object that will be passed as
                          the first parameter to all for most of the DSP methods
                          (dspReceive, dspSend). Those methods should use the
                          first passed parameter, and not the "this" variable,
                          for any connection-specific properties or
                          methods--because the dsp object is acting as a proxy
                          to another system to use the "this" variable would
                          instead be acting on the remote system. |  
                    | description: | This function creates a
                          new DSP object, or returns null
                          on error. Note that calling this function itself
                          accomplishes very little unless you build up an
                          appropriate DSP object by adding open, close, and
                          transport functions. A new DSP object can be created
                          with just new DSP(),
                          but it will be unusable without transport functions.
                          See the introduction, under creating
                          a DSP object, for more
                          information about setting up a proper DSP object. The
                          first optional parameter is the open function to use.
                          Once the object has been created, this function is
                          called with any additional parameters passed to DSP().
                          The result of this call is set the dspConnection
                          member of the newly created object, and is only used
                          to pass as the first parameters to the dspSend,
                          dspReceive, and dspCloseConnection
                          methods. If openFunction
                          is supplied and returns null,
                          then it is considered an error and the DSP
                          construction fails. |  
                    | see: | #link <sedsp> |  
                    | example: | function fileOpen(
                          filename ) {  return Clib.fopen(
                          filename, "wb" ); } var connection = new
                          DSP( fileOpen, "c:\tempfile.dat" ); // This will call
                          fileOpen and assign the result to //
                          connection.dspConnection. If it was null, // then the DSP
                          connection will fail |  
 
 DSP dspCloseConnection() 
                
                  
                    | syntax: | dsp.closeConnection(connection) |  
                    | where: | connection - The
                          original connection that was created with the
                          openFunction passed to new
                        DSP() |  
                    | return: | void. |  
                    | description: | This function is
                          responsible for terminating the connection that was
                          opened at the time the DSP object was created. This is
                          an optional function, and if not supplied then nothing
                          will be done with the connection. See the
                          introduction, under creating
                          a DSP object, for an
                          example of how to implement this function. |  
                    | see: | #link <sedsp>,
                        DSP() |  
 
 DSP dspReceive() 
                
                  
                    | syntax: | dsp.dspReceive(connection,
                          buffer, bufferLength,  timeout) |  
                    | where: | connection - The
                          original connection that was returned from the
                          openFunction passed to new
                        DSP() buffer - A buffer which
                          is to be filled with data. This variable must be
                          passed by reference (with the & operator). bufferLength - The
                          maximum amount of data to read timeout - The maximum
                          amount of time to wait (in milliseconds) for data to
                          be ready for reading on the connection |  
                    | return: | number - The number of
                          bytes read, or -1 on error |  
                    | description: | This function is
                          responsible for getting data from the connection. This
                          function should wait up to timeout
                          milliseconds for data to be available on the
                          connection. If there is no data available, then this
                          function should return 0. Otherwise, the function
                          should read up to bufferLength
                          bytes from the connection and put the data into buffer.
                          Note that this means that buffer
                          must be passed by reference. If there is some sort of
                          error, then this function should either throw an
                          error, or return -1. See introduction, under creating
                          a DSP object, for an
                          example of how to implement this function. Note that
                          the function need not wait for the entire buffer to be
                          filled, it should read only as much data as is
                          available to be read. |  
                    | see: | #link <sedsp>,
                        DSP dspSend() |  
 
 DSP dspSend() 
                
                  
                    | syntax: | dsp.dspSend(connection,
                          buffer, timeout) |  
                    | where: | connection - The
                          original connection that was returned from the
                          openFunction passed to new
                        DSP() buffer - The buffer to
                          send timeout - The maximum
                          amount of time to wait (in milliseconds) for data to
                          be ready for writing on the connection |  
                    | return: | number - The number of
                          bytes written, or -1 on error |  
                    | description: | This function is
                          responsible for sending data across the connection
                          (the one returned by the openFunction passed to the
                          DSP constructor). Its behavior is similar to that of
                          dspReceive(). It should wait up until timeout
                          for data to be ready, and then send as much as
                          possible along the connection (up to the length of buffer).
                          If the timeout expires, the function should return 0.
                          If there was some sort of error, then an error should
                          be thrown, or -1 returned. Otherwise, the number of
                          bytes written should be returned. Throwing an error is
                          often more descriptive than the generic failure
                          message. See introduction, under creating
                          a DSP object, for an
                          example of how to implement this function. |  
                    | see: | #link <sedsp>,
                        DSP dspReceive() |  
 
 DSP dspLoad() 
                
                  
                    | syntax: | dsp.dspLoad(code) |  
                    | where: | code - String of code to
                          load on the remote server |  
                    | return: | void. |  
                    | description: | This function loads the
                          specified code into the global context on the remote
                          server. Any code that you execute will remain on the
                          remote server. This function is designed to load
                          functions on the remote server so that they may be
                          called by the client. This function does not wait for
                          a return value from the host. As a consequence, remote
                          errors will not be immediately reported. They will be
                          reported next time a client routine (calling a
                          function, getting/putting a value) queries the server.
                          Note that if you wish to execute remote code and get a
                          return value, the global eval() method for the server
                          should be used, although the changes will not be
                          permanent. |  
                    | see: | #link <sedsp> |  
                    | example: | function foo() {
                          Screen.writeln("Hello!"); } // This code will make
                          "foo = new Function(...)" // to set up the
                          function on the remote server. connection.dspLoad( "foo
                          = " + ToSource(foo) ); connection.foo(); // foo is now a global
                          function on the server |  
 
 DSP dspService() 
                
                  
                    | syntax: | dsp.dspService() |  
                    | return: | boolean - A value
                          indicating whether the connection is still open. |  
                    | description: | This is the main
                          server-side function. Although it can be used by any
                          DSP object, it is intended to be the server side of
                          the client-server model. When called, it will wait
                          until an incoming packet is received and then service
                          that packet appropriately. The method will return false
                          if the packet received was a close command, in which
                          case the connection has been closed, and an explicit
                          call to dspClose
                          is not necessary. It is designed to be called
                          repeatedly until the connection is closed. |  
                    | see: | #link <sedsp> |  
                    | example: | // Assume 'connection'
                          is a valid connection while(
                          connection.dspService() )  ; // At this point, the
                          connection has been // successfully closed |  
 
 DSP dspClose() 
                
                  
                    | syntax: | dsp.dspClose() |  
                    | return: | void. |  
                    | description: | This function closes the
                          DSP connection. First, it sends a close command to the
                          remote host, signaling that the connection is closing.
                          It then calls the dspCloseConnection
                          method if it exists, passing the original connection
                          variable returned by the open function when this
                          connection was created. |  
                    | see: | #link <sedsp> |  
                    | example: | connection.dspClose(); |  
 
 DSP dspGetValue() 
                
                  
                    | syntax: | dsp.dspGetValue() |  
                    | return: | variable - remote value
                          of the current DSP reference. |  
                    | description: | This function provides
                          an explicit way to convert a DSP reference into a
                          value. Such conversion is done automatically when the
                          reference is converted to a primitive, or a value is
                          assigned to a reference. See the introduction, under creating
                          a DSP object, for more
                          information on DSP references and getting remote
                          values. |  
                    | see: | #link <sedsp> |  
                    | example: | var reference =
                          connection.globalValue; var value =
                          connection.globalValue.dspGetValue(); reference = 5; // This
                          will change the remote value value = 6;  // This will change the
                          local copy, not the remote |  
 
 DSP dspSecurityInit() 
                
                  
                    | syntax: | dsp.dspSecurityInit(secureVar) |  
                    | where: | secureVar - private
                          storage for the DSP security. The member 'dsp' is
                          preset to the DSP object. Remember, the DSP object can
                          be seen by the running script, but not the secure
                          variable itself. |  
                    | return: | void. |  
                    | description: | The dspSecurityInit
                          function turns on security for a DSP object. This
                          means when the remote client tries to run a script on
                          your machine using DSP, it will be run with your
                          security manager in effect. In the case of DSP, each
                          security function (jseSecurityInit, jseSecurityTerm,
                          and jseSecurityGuard) has an exactly corresponding
                          function, i.e., dspSecurityInit, dspSecurityTerm, and
                          dspSecurityGuard. In the security initialization
                          function, you'll typically select some functions to be
                          allowed, and let all others be vetoed. |  
                    | see: | #link <sedsp>,
                        DSP dspSecurityTerm(),
                        DSP dspSecurityGuard() |  
                    | example: | function
                          iDSP.dspSecurityGuard( conn ) { 
                          myfunc.setSecurity(jseSecureAllow); 
                          myotherfunc.setSecurity(jseSecureGuard); } |  
 
 DSP dspSecurityTerm() 
                
                  
                    | syntax: | dsp.dspSecurityTerm(secureVar) |  
                    | where: | secureVar - private
                          storage for the DSP security. |  
                    | return: | void. |  
                    | description: | This function is
                          typically not needed, but you can use it to cleanup
                          anything you initialized in the DSP security
                          initialization function. |  
                    | see: | #link <sedsp>,
                        DSP dspSecurityInit(),
                        DSP dspSecurityGuard() |  
 
 DSP dspSecurityGuard() 
                
                  
                    | syntax: | dsp.dspSecurityGuard(secureVar,
                          function,  params) |  
                    | where: | function - the function
                          being called secureVar - private
                          storage for the DSP security. params - whatever
                          parameters are passed to the function |  
                    | return: | void. |  
                    | description: | If a DSP object is given
                          a dspSecurityGuard function (exactly like any of the
                          other DSP callback functions), when it tries to call
                          any function not part of the script (i.e. one of your
                          functions or a wrapper function), the security guard
                          is called for approval. You must provide a
                          dspSecurityInit for security to be activated. Only
                          those functions the security initialization function
                          marks as guarded will use this function. |  
                    | see: | #link <sedsp>,
                        DSP dspSecurityInit(),
                        DSP dspSecurityTerm() |  
 
 DSP object static propertiesDSP.remote 
                
                  
                    | syntax: | DSP.remote |  
                    | description: | This global property of
                          the DSP object is used to make calls back to the
                          remote client from within a function. When the first
                          DSP object in a script is created, this gets assigned
                          to that value. From then on, whenever a packet needs
                          to be serviced, this value is set (and later restored)
                          to the object representing the incoming connection.
                          This allows for multiple connections, and lets the
                          function easily call back the appropriate client. Note
                          that within a dspLoad
                          call, the client does not wait for a response, and so
                          trying to call on the client will yield no result
                          until the server is queried again. |  
                    | see: | #link <sedsp> |  
                    | example: | // Assume the client
                          calls this: serverConn.printRemote("hi"); // And the server side
                          looks like this: function printRemote(
                          string ) { 
                          DSP.remote.Screen.write( string ); } // This will print out
                          "hi" on the client machine |  
 |