topical media & game development

talk show tell print

lib-js-terminal-termlib-socket.js / js



  /*
    termlib_socket.js - termlib.js Socket Extension v.1.02
    applies to the termlib.js license (cf: <http://www.masswerk.at/termlib/>)
  
    (c) Norbert Landsteiner 2003-2007
    mass:werk - media environments
    <http://www.masswerk.at>
  
    load termlib.js first!
  
    Syntax is JS 1.5 or higher (no NS4 compatibility)
  
  # Synopsis:
    Integrates async XMLHttpRequests (AJAX/JSON) tightly into termlib.js
  
  # Example:
  
    myTerm = new Terminal( { handler: myTermHandler } );
    myTerm.open();
  
    function myTermHandler() {
      this.newLine();
      if (this.lineBuffer == 'get file') {
         myTerm.send(
           {
             url: 'myservice',
             data: {
                 book: 'theBook',
                 chapter: 7,
                 page: 45
               },
             callback: myCallback
            }
         );
         return;
      }
      else {
         // ...
      }
      this.prompt();
    }
  
    function myCallback() {
            if (this.socket.success) {
                    this.write(this.socket.responseText);
            }
            else {
                    this.write('OOPS: ' + this.socket.status + ' ' + this.socket.statusText);
                    if (this.socket.errno) {
                            this.newLine();
                            this.write('Error: ' + this.socket.errstring);
                    }
            }
            this.prompt();
    }
  
  # Documentation:
  
    for usage and description see readme.txt chapter 13:
    <http://www.masswerk.at/termlib/readme.txt>
  
    or refer to the sample page:
    <http://www.masswerk.at/termlib/sample_socket.html>
  
  # Version History:
  
    2007-03:  v. 1.01
    2007-04:  v. 1.02  just a little clean up
  
  */
  
  if (window.Terminal && typeof window.Terminal == 'function') {
    
          Terminal.prototype._HttpSocket = function() {
                  var req=null;
                  if (window.XMLHttpRequest) {
                          try {
                                  req=new XMLHttpRequest();
                          }
                          catch(e) {}
                  }
                  else if (window.ActiveXObject) {
                          var prtcls=this._msXMLHttpObjects;
                          for (var i=0; i<prtcls.length; i++) {
                                  try {
                                          req=new ActiveXObject(prtcls[i]);
                                          if (req) {
                                                  // shorten proto list to working element
                                                  if (prtcls.length>1) this.prototype._msXMLHttpObjects= [ prtcls[i] ];
                                                  break;
                                          }
                                  }
                                  catch(e) {}
                          }
                  }
                  this.request=req;
                  this.url;
                  this.data=null;
                  this.query='';
                  this.timeoutTimer=null;
                  this.localMode=Boolean(window.location.href.search(/^file:/i)==0);
                  this.error=0;
          }
          
          Terminal.prototype._HttpSocket.prototype = {
                  version: '1.02',
                  // config
                  useXMLEncoding: false, // use ";" as separator if true, "&" else
                  defaulTimeout: 10000,  // request timeout in ticks (milliseconds)
                  defaultMethod: 'GET',
                  forceNewline: true,    // translate line-breaks in responseText to newlines
                  
                  // static const
                  errno: {
                          OK: 0,
                          NOTIMPLEMENTED: 1,
                          FATALERROR: 2,
                          TIMEOUT: 3,
                          NETWORKERROR: 4,
                          LOCALFILEERROR: 5
                  },
                  errstring: [
                          '',
                          'XMLHttpRequest not implemented.',
                          'Could not open XMLHttpRequest.',
                          'The connection timed out.',
                          'Network error.',
                          'The requested local document was not found.'
                  ],
                  
                  // private static data
                  _msXMLHttpObjects: [
                          'Msxml2.XMLHTTP',
                          'Microsoft.XMLHTTP',
                          'Msxml2.XMLHTTP.5.0',
                          'Msxml2.XMLHTTP.4.0',
                          'Msxml2.XMLHTTP.3.0'
                  ],
                  
                  // internal methods
                  serializeData: function() {
                          this.query=this.serialize(this.data);
                  },
                  serialize: function(data) {
                          var v='';
                          if( data != null ) {
                                  switch (typeof data) {
                                          case 'object':
                                                  var d=[];
                                                  if (data instanceof Array) {
                                                          // array
                                                          for (var i=0; i<data.length; i++) {
                                                                  d.push(this.serialize(data[i]));
                                                          }
                                                          v= d.join(',');
                                                          break;
                                                  }
                                                  for (var i in data) {
                                                          switch (typeof data[i]) {
                                                                  case 'object':
                                                                          d.push(encodeURIComponent(i)+'='+this.serialize(data[i]));
                                                                          break;
                                                                  default:
                                                                          d.push(encodeURIComponent(i)+'='+encodeURIComponent(data[i]));
                                                                          break;
                                                          }
                                                  }
                                                  v= (this.useXMLEncoding)? d.join(';') : d.join('&');
                                                  break;
                                          case 'number':
                                                  v=String(data);
                                                  break;
                                          case 'string':
                                                  v=encodeURIComponent(data);
                                                  break;
                                          case 'boolean':
                                                  v=(data)? '1':'0';
                                                  break;
                                  }
                          }
                          return v;
                  },
                  toCamelCase: function(s) {
                          if (typeof s!='string') s=String(s);
                          var a=s.toLowerCase().split('-');
                          var cc=a[0];
                          for (var i=1; i<a.length; i++) {
                                  p=a[i];
                                  if (p.length) cc+=p.charAt(0).toUpperCase()+p.substring(1);
                          }
                          return cc;
                  },
                  callbackHandler: function() {
                          if (this.termRef.closed) return;
                          var r=this.request;
                          if (this.error==0 && r.readyState!=4) return;
                          if (this.timeoutTimer) {
                                  clearTimeout (this.timeoutTimer);
                                  this.timeoutTimer = null;
                          }
                          var success=false;
                          var failed=true;
                          var response={
                                  headers: {}
                          };
                          if (this.localMode) {
                                  if (this.error && this.error<this.errno.NETWORKERROR) {
                                          response.status=0;
                                          response.statusText='Connection Error';
                                          response.responseText='';
                                          response.responseXML=null;
                                  }
                                  else if (this.error || r.responseText==null) {
                                          failed=false;
                                          response.status=404;
                                          response.statusText='Not Found';
                                          response.responseText='The document '+this.url+' was not found on this file system.';
                                          response.responseXML=null;
                                          this.error=this.errno.LOCALFILEERROR;
                                  }
                                  else {
                                          success=true;
                                          failed=false;
                                          response.status=200;
                                          response.statusText='OK';
                                          response.responseText=r.responseText;
                                          response.responseXML=r.responseXML;
                                  }
                          }
                          else {
                                  try {
                                          if (!this.error) {
                                                  if (typeof r == 'object' && r.status != undefined)  {
                                                          failed=false;
                                                          if ((r.status >= 200) && (r.status < 300)) {
                                                                  success=true;
                                                          }
                                                          else if (r.status >= 12000) {
                                                                  // MSIE network error
                                                                  failed=true;
                                                                  this.error=this.errno.NETWORKERROR;
                                                          }
                                                  }
                                          }
                                  }
                                  catch(e) {}
                                  if (!failed) {
                                          response.status=r.status;
                                          response.statusText= (r.status==404)? 'Not Found':r.statusText; // force correct header
                                          response.responseText=r.responseText;
                                          response.responseXML=r.responseXML;
                                          if (this.getHeaders) {
                                                  if (this.getHeaders instanceof Array) {
                                                          for (var i=0; i<this.getHeaders.length; i++) {
                                                                  var h=this.getHeaders[i];
                                                                  try {
                                                                          response.headers[this.toCamelCase(h)]=r.getResponseHeader(h);
                                                                  }
                                                                  catch(e) {}
                                                          }
                                                  }
                                                  else {
                                                          for (var h in this.getHeaders) {
                                                                  try {
                                                                          response.headers[this.toCamelCase(h)]=r.getResponseHeader(h);
                                                                  }
                                                                  catch(e) {}
                                                          }
                                                  }
                                          }
                                  }
                                  else {
                                          response.status=0;
                                          response.statusText='Connection Error';
                                          response.responseText='';
                                          response.responseXML=null;
                                  }
                          }
                          if (this.forceNewline) response.responseText=response.responseText.replace(/\r\n?/g, '\n');
                          response.url=this.url;
                          response.data=this.data;
                          response.query=this.query;
                          response.method=this.method;
                          response.success=success;
                          response.errno=this.error;
                          response.errstring=this.errstring[this.error];
                          var term=this.termRef;
                          term.socket=response;
                          if (this.callback) {
                                  if (typeof this.callback=='function') {
                                          this.callback.apply(term);
                                  }
                                  else if (window[this.callback] && typeof window[this.callback]=='function') {
                                          window[this.callback].apply(term);
                                  }
                                  else {
                                          term._defaultServerCallback();
                                  }
                          }
                          else {
                                  term._defaultServerCallback();
                          }
                          delete term.socket;
                          this.request=null;
                          this.callback=null;
                  },
                  timeoutHandler: function() {
                          this.error = this.errno.TIMEOUT;
                          try {
                                  this.request.abort();
                          }
                          catch(e) {}
                          if (!this.localMode) this.callbackHandler();
                  }
          }
          
          Terminal.prototype.send = function( opts ) {
                  var soc = new this._HttpSocket();
                  if (opts) {
                          if (typeof opts.method == 'string') {
                                  switch (opts.method.toLowerCase()) {
                                          case 'post':
                                                  soc.method='POST'; break;
                                          case 'get':
                                                  soc.method='GET'; break;
                                          default:
                                                  soc.method=soc.defaultMethod.toUpperCase();
                                  }
                          }
                          else {
                                  soc.method=soc.defaultMethod;
                          }
                          if (opts.postbody != undefined) {
                                  soc.method='POST';
                                  soc.query=opts.postbody;
                                  soc.data=opts.data;
                          }
                          else if (opts.data != undefined) {
                                  soc.data=opts.data;
                                  soc.serializeData();
                          }
                          if (opts.url) soc.url=opts.url;
                          if (opts.getHeaders && (typeof opts.getHeaders=='object')) {
                                  soc.getHeaders=opts.getHeaders;
                          }
                  }
                  else {
                          opts = {}
                          soc.method=soc.defaultMethod;
                  }
                  var uri=soc.url;
                  if (soc.method=='GET') {
                          if (soc.query) {
                                  uri+= (uri.indexOf('?')<0)?
                                          '?'+soc.query :
                                          (soc.useXMLEncoding)? ';'+soc.query : '&'+soc.query;
                          }
                          if (!soc.localMode) {
                              // add a random value to the query string (force a request)
                              var uniqueparam= '_termlib_reqid=' +new Date().getTime()+'_'+Math.floor(Math.random()*100000);
                              uri+= (uri.indexOf('?')<0)?
                                          '?'+uniqueparam :
                                          (soc.useXMLEncoding)? ';'+uniqueparam : '&'+uniqueparam;
                          }
                  }
                  soc.callback=opts.callback;
                  soc.termRef=this;
                  if (!soc.request) {
                          soc.error = soc.errno.NOTIMPLEMENTED;
                          soc.callbackHandler();
                          return;
                  }
                  else {
                          try {
                                  if (opts.userid!=undefined) {
                                          if (opts.password!=undefined) {
                                                  soc.request.open(soc.method, uri, true, opts.userid, opts.password);
                                          }
                                          else {
                                                  soc.request.open(soc.method, uri, true, opts.userid);
                                          }
                                  }
                                  else {
                                          soc.request.open(soc.method, uri, true);
                                  }
                          }
                          catch(e) {
                                  soc.error = soc.errno.FATALERROR;
                                  soc.callbackHandler();
                                  return;
                          }
                          var body=null;
                          if (soc.method == 'POST') {
                                  try {
                                          soc.request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
                                  }
                                  catch(e) {}
                                  body=soc.query;
                          }
                          if (opts.headers && typeof opts.headers == 'objects') {
                                  for (var i in opts.headers) {
                                          try {
                                                  soc.request.setRequestHeader(i, opts.headers[i]);
                                          }
                                          catch(e) {}
                                  }
                          }
                          if (opts.mimetype && soc.request.overrideMimeType) {
                                  try {
                                          soc.request.overrideMimeType(opts.mimetype);
                                          // force "Connection: close" (Bugzilla #246651)
                                          soc.request.setRequestHeader('Connection', 'close');
                                  }
                                  catch(e) {}
                          }
                          
                          var timeoutDelay=(opts.timeout && typeof opts.timeout=='number')? opts.tiomeout : soc.defaulTimeout;
                          
                          soc.request.onreadystatechange=function() { soc.callbackHandler(); };
                          try {
                                  soc.request.send(body);
                          }
                          catch(e) {
                                  if (soc.localMode) {
                                          soc.request.onreadystatechange=null;
                                          soc.request.abort();
                                          soc.error = soc.errno.LOCALFILEERROR;
                                  }
                                  else {
                                          soc.request.onreadystatechange=null;
                                          try {
                                                  soc.request.abort();
                                          }
                                          catch(e2) {}
                                          soc.error = soc.errno.NETWORKERROR;
                                  }
                                  soc.callbackHandler();
                                  return true;
                          }
                          soc.timeoutTimer = setTimeout(function() { soc.timeoutHandler() }, timeoutDelay);
                  }
          }
          Terminal.prototype._defaultServerCallback = function() {
                  if (this.socket.success) {
                          // output im more-mode
                          this.write('Server Response:\%n'+this.socket.responseText, true);
                  }
                  else {
                          var s='Request failed: '+this.socket.status+' '+this.socket.statusText;
                          if (this.socket.errno) s+='\%n'+this.socket.errstring;
                          this.write(s);
                          this.prompt();
                  }
          }
  
  }
  
  // eof


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.