diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..efb64a6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/_ReSharper.Node.Net/ +/**/bin/ +/**/obj/ +*.user +*.suo \ No newline at end of file diff --git a/IronJS-Tests/IronJS-FS-Tests.csproj b/IronJS-Tests/IronJS-FS-Tests.csproj index 26fb4fe..1698737 100644 --- a/IronJS-Tests/IronJS-FS-Tests.csproj +++ b/IronJS-Tests/IronJS-FS-Tests.csproj @@ -36,12 +36,6 @@ - - - - - - diff --git a/IronJS-Tests/Program.cs b/IronJS-Tests/Program.cs index 560939f..b305097 100644 --- a/IronJS-Tests/Program.cs +++ b/IronJS-Tests/Program.cs @@ -11,8 +11,8 @@ class Program { static void Main( string[] args ) { Server instance = new Server(); - instance.evalCommandlineArgument(); - instance.runEventLoop(); + instance.EvalCommandlineArgument(); + instance.RunEventLoop(); } } } diff --git a/IronJS/Node.Net.csproj b/IronJS/Node.Net.csproj index c4d423e..e2a226b 100644 --- a/IronJS/Node.Net.csproj +++ b/IronJS/Node.Net.csproj @@ -44,12 +44,6 @@ ..\lib\ironjs-0.2-clr4-x64\IronJS.dll - - - - - - diff --git a/IronJS/commonjs.cs b/IronJS/commonjs.cs index a6057d3..0c18f98 100644 --- a/IronJS/commonjs.cs +++ b/IronJS/commonjs.cs @@ -1,14 +1,11 @@ -using System; -using System.IO; +using System.IO; using System.Collections.Generic; -using System.Linq; -using System.Text; namespace Node.Net { - class commonjs + internal static class CommonJS { - public static Stack RequireStack = new Stack(); + public static readonly Stack RequireStack = new Stack(); /** * Find a a given js file according to CommonJS search diff --git a/IronJS/netserver.cs b/IronJS/netserver.cs index 8ba2d33..88eb5c2 100644 --- a/IronJS/netserver.cs +++ b/IronJS/netserver.cs @@ -15,19 +15,19 @@ */ namespace Node.Net { - public class NetStream : IronJS.CommonObject + public class NetStream : CommonObject { // XXX making stream public to work around incomplete design - fix this public Stream stream; // TODO: callbacks will be JS functions, should probably use // List - ArrayList dataCallbacks = new ArrayList(); - ArrayList endCallbacks = new ArrayList(); + readonly ArrayList dataCallbacks = new ArrayList(); + readonly ArrayList endCallbacks = new ArrayList(); // TODO: this should be defined somewhere else // Using 1k buffer - experimentally, seems to be what node.js uses - int bufferSize = 1024; + const int bufferSize = 1024; public NetStream( Stream stream, IronJS.Environment env ) : base( env, env.Maps.Base, env.Prototypes.Object ) { this.stream = stream; @@ -52,7 +52,7 @@ public void ReadCallback( IAsyncResult result ) { if( bytesRead > 0 ) { // queue work before calling another read, could be out of order otw - Server.instance.queueWorkItem( new Callback() { name = "stream:raiseDataEvent", callback = raiseDataEvent, args = new object[] { chunk } } ); + Server.Instance.QueueWorkItem( new Callback { name = "stream:raiseDataEvent", callback = raiseDataEvent, args = new object[] { chunk } } ); byte[] nextBuffer = new byte[ bufferSize ]; this.stream.BeginRead( nextBuffer, 0, bufferSize, ReadCallback, nextBuffer ); } @@ -61,7 +61,7 @@ public void ReadCallback( IAsyncResult result ) { // remote end of socket, not sure if raising "end" when there // is no more data is the right thing to do. It does the right thing // when using Telnet as the client - Server.instance.queueWorkItem( new Callback() { name = "stream:raiseEndEvent", callback = raiseEndEvent, args = new object[]{} } ); + Server.Instance.QueueWorkItem( new Callback { name = "stream:raiseEndEvent", callback = raiseEndEvent, args = new object[]{} } ); } } @@ -76,7 +76,7 @@ public void end() { this.stream.Close(); } public void addListener( string eventname, IronJS.FunctionObject callback ) { - Server.instance.Listeners++; + Server.Instance.Listeners++; log.Trace( "NetStream: adding listener: " + eventname ); if( eventname == "data" ) { dataCallbacks.Add( callback ); @@ -87,11 +87,11 @@ public void addListener( string eventname, IronJS.FunctionObject callback ) { } public void removeAllListeners( string eventname ) { if( eventname == "data" ) { - Server.instance.Listeners -= dataCallbacks.Count; + Server.Instance.Listeners -= dataCallbacks.Count; dataCallbacks.Clear(); } else if( eventname == "end" ) { - Server.instance.Listeners -= endCallbacks.Count; + Server.Instance.Listeners -= endCallbacks.Count; endCallbacks.Clear(); } } @@ -129,13 +129,13 @@ public void raiseEndEvent( object[] args ) { } // class - public class NetServer : IronJS.CommonObject + public class NetServer : CommonObject { TcpListener tcpServer; - ArrayList listeningCallbacks = new ArrayList(); - ArrayList connectionCallbacks = new ArrayList(); - ArrayList closeCallbacks = new ArrayList(); + readonly ArrayList listeningCallbacks = new ArrayList(); + readonly ArrayList connectionCallbacks = new ArrayList(); + readonly ArrayList closeCallbacks = new ArrayList(); public NetServer( IronJS.FunctionObject callback, IronJS.Environment env ) : base( env, env.Maps.Base, env.Prototypes.Object ) { // have to set this stuff up. not sure why yet @@ -162,7 +162,7 @@ public CommonObject listen( object in_port, string host ) { this.tcpServer = new TcpListener( ipAddress, port ); log.Trace( "net.Server.listen(): starting tcp server" ); this.tcpServer.Start(); - Server.instance.queueWorkItem( new Callback { callback = raiseListeningEvent, args = new object[]{} } ); + Server.Instance.QueueWorkItem( new Callback { callback = raiseListeningEvent, args = new object[]{} } ); this.tcpServer.BeginAcceptTcpClient( listenerCallback, null ); return this; } @@ -175,7 +175,7 @@ public void listenerCallback( IAsyncResult result ) { TcpClient client = this.tcpServer.EndAcceptTcpClient( result ); NetStream stream = new NetStream( client.GetStream(), Env ); - Server.instance.queueWorkItem( new Callback { callback = raiseConnectionEvent, args = new object[]{ stream } } ); + Server.Instance.QueueWorkItem( new Callback { callback = raiseConnectionEvent, args = new object[]{ stream } } ); // kick off async read stream.read(); @@ -209,28 +209,28 @@ public void raiseConnectionEvent( object[] args ) { func.Compiler.compileAs>(func); fun.Invoke(func, this, stream ); */ - func.Call( this, stream ); + func.Call( this, stream ); } } public void removeAllListeners( string eventname ) { if( eventname == "listening" ) { - Server.instance.Listeners -= listeningCallbacks.Count; + Server.Instance.Listeners -= listeningCallbacks.Count; listeningCallbacks.Clear(); } else if( eventname == "connection" ) { - Server.instance.Listeners -= connectionCallbacks.Count; + Server.Instance.Listeners -= connectionCallbacks.Count; connectionCallbacks.Clear(); } else if( eventname == "close" ) { - Server.instance.Listeners -= closeCallbacks.Count; + Server.Instance.Listeners -= closeCallbacks.Count; closeCallbacks.Clear(); } } public void addListener( string eventname, IronJS.FunctionObject callback) { log.Trace( "NetServer - adding listener: " + eventname ); - Server.instance.Listeners++; + Server.Instance.Listeners++; if( eventname == "listening" ) { listeningCallbacks.Add( callback ); } @@ -248,19 +248,19 @@ public void addListener( string eventname, IronJS.FunctionObject callback) { // provides the 'net' namespace // TODO: rename this class - public class net : IronJS.CommonObject + public class net : CommonObject { public net( IronJS.Environment env ) : base( env, env.Maps.Base, env.Prototypes.Object ) { - var objMethod = Utils.createHostFunction>( Env, CreateServer ); + var objMethod = Utils.createHostFunction>( Env, CreateServer ); log.Trace( objMethod ); this.Put( "createServer", objMethod ); } - public IronJS.CommonObject CreateServer( IronJS.FunctionObject callback ) { + public CommonObject CreateServer( FunctionObject callback ) { log.Trace( "net.createServer() called." ); - Net.NetServer server = new Net.NetServer( callback, Env ); + NetServer server = new Net.NetServer( callback, Env ); log.Trace( server ); return ( server ); } diff --git a/IronJS/server.cs b/IronJS/server.cs index 0cbce20..7d0d551 100644 --- a/IronJS/server.cs +++ b/IronJS/server.cs @@ -8,7 +8,6 @@ using System.Threading; using System.IO; -using System.Text; using System.Collections; using System.Collections.Generic; using System; @@ -21,40 +20,50 @@ public class Server { // temp hack global used to access event queue // by other modules - public static Server instance; + public static Server Instance + { + get { return instance;} + } + + private static readonly Server instance; // number of registered callbacks active public int Listeners = 0; // dispatch queue and signalling primitive for main event loop - private ManualResetEvent manualResetEvent = new ManualResetEvent( false ); - private Queue workItems = new Queue(); + private readonly ManualResetEvent manualResetEvent = new ManualResetEvent( false ); + private readonly Queue workItems = new Queue(); // toplevel JS execution context used for all JS code - private static IronJS.Hosting.CSharp.Context ctx = new IronJS.Hosting.CSharp.Context(); + private static readonly IronJS.Hosting.CSharp.Context ctx = new IronJS.Hosting.CSharp.Context(); - private static Node.Net.net netObj = new Net.net( ctx.Environment ); + private static readonly net netObj = new net( ctx.Environment ); // TODO: re-add after httpserver.cs is converted to IJS 0.2 // private static http httpObj = new http( ctx.Environment ); + static Server() + { + instance = new Server(); + } + public static void Main() { // eval js file given as first commandline arg and // run the event loop - runEventLoop() always blocks, unlike node.js // which returns if no more callbacks are registered - instance = new Server(); - instance.evalCommandlineArgument(); - instance.runEventLoop(); + Instance.EvalCommandlineArgument(); + Instance.RunEventLoop(); } private static List requireStack = new List(); - /** - * implements require() for importing js files/namespaces - * - * file - the literal expression passed to require() in js. - * Might be abs or rel path + filename. - */ - public static IronJS.CommonObject Require( string file ) { + /// + /// Implements require() for importing js files/namespaces + /// + /// The literal expression passed to require() in js. Might be absolute or relative path + filename. + /// + /// The contents of the . + /// + public static CommonObject Require( string file ) { // TODO: could possibly break this by doing require('undefined'); if( String.IsNullOrWhiteSpace( file ) || String.IsNullOrEmpty( file ) || file == "undefined" ) { throw new Exception( "invalid file spec passed to require()" ); @@ -71,23 +80,29 @@ public static IronJS.CommonObject Require( string file ) { } // otherwise invoke CommonJS search rules - commonjs.SetRequireStack( file ); + CommonJS.SetRequireStack( file ); string filename = Path.GetFileName( file ); - FileStream fs; - string filepath = commonjs.FindFile( filename ); - fs = new FileStream( filepath, FileMode.Open, FileAccess.Read ); - - string code = new StreamReader( fs ).ReadToEnd(); - // extra semicolon provided after file contents.. just in case - code = "var exports = {}; " + code + "; exports;"; - IronJS.CommonObject retval = ctx.Execute( code ); - commonjs.RequireStack.Pop(); - return retval; + string filepath = CommonJS.FindFile( filename ); + + using (var fs = new FileStream(filepath, FileMode.Open, FileAccess.Read)) + { + string code = new StreamReader(fs).ReadToEnd(); + // extra semicolon provided after file contents.. just in case + code = "var exports = {}; " + code + "; exports;"; + CommonObject retval = ctx.Execute(code); + // This should probably be inside a finally so it's always executed? [asbjornu] + CommonJS.RequireStack.Pop(); + return retval; + } } - // threadsafe enqueue function - public void queueWorkItem( object item ) { + + /// + /// Threadsafe enqueue function. + /// + /// The item. + public void QueueWorkItem( object item ) { log.Trace( "queueWorkItem(): queuing item: " + ( ( Callback )item ).name ); log.Trace( "queueWorkItem(): acquiring lock: " + workItems ); Monitor.Enter( workItems ); @@ -102,31 +117,19 @@ public void queueWorkItem( object item ) { log.Trace( "queueWorkItem: released lock" ); } } - - private string readFile( string filename ) { - string fileContents; - StreamReader streamReader = new StreamReader( filename ); - try { - fileContents = streamReader.ReadToEnd(); - return fileContents; - } - finally { - streamReader.Close(); - } - } - - public void evalCommandlineArgument() { + + public void EvalCommandlineArgument() { string[] args = System.Environment.GetCommandLineArgs(); if( args.Length != 2 ) { Console.WriteLine( "usage: node " ); System.Environment.Exit( 1 ); } // string script = readFile( args[1] ); - commonjs.SetRequireStack( args[ 1 ] ); - ReadJsFile( args[ 1 ] ); + CommonJS.SetRequireStack( args[ 1 ] ); + SetupContext( args[ 1 ] ); } - public void runEventLoop() { + public void RunEventLoop() { while( this.Listeners > 0 ) { log.Trace( "event loop running" ); Callback callback = null; @@ -161,43 +164,33 @@ public void runEventLoop() { } // while } - /** - * This is badly named - really it sets up the - * global context and then executes the file given - * on within that context. - */ - public void ReadJsFile( string in_filename ) { - - commonjs.SetRequireStack( in_filename ); + /// + /// Sets up the global context and then executes the file given on within that context. + /// + /// The name of the file to execute. + public void SetupContext( string filename ) { + CommonJS.SetRequireStack( filename ); // string pathpart = Path.GetDirectoryName( in_filename ); // path = Directory.GetCurrentDirectory() + pathpart; // log.Trace( "path of js file: " + path ); var emit = - Utils.createHostFunction>( - ctx.Environment, ( obj ) => { - Console.WriteLine( IronJS.TypeConverter.ToString( obj ) ); - } - ); - ctx.SetGlobal( "puts", emit ); + Utils.createHostFunction>( + ctx.Environment, obj => Console.WriteLine( TypeConverter.ToString( obj ) )); + ctx.SetGlobal( "puts", emit ); - var require = - Utils.createHostFunction>( - ctx.Environment, ( obj ) => { - return Require( obj ); - } - ); - ctx.SetGlobal( "require", require ); + var require = Utils.createHostFunction>( ctx.Environment, Require ); + ctx.SetGlobal( "require", require ); // Forms the `net" namespace - ctx.SetGlobal( "net", netObj ); + ctx.SetGlobal( "net", netObj ); // Forms the `http" namespace // TODO: re-add after httpserver.cs is converted to IJS 0.2 // ctx.SetGlobal( "http", httpObj ); - ctx.ExecuteFile( in_filename ); + ctx.ExecuteFile( filename ); } } // class diff --git a/ironjs-fs/.gitignore b/ironjs-fs/.gitignore new file mode 100644 index 0000000..460e47d --- /dev/null +++ b/ironjs-fs/.gitignore @@ -0,0 +1,6 @@ +/bin/ +/obj/ +/_ReSharper.Node.Net/ +/*.csproj.user +/*.suo +/*.ReSharper.user