Friday, June 22, 2012

Abstraction? Encapsulation? Integration?

So, I'm having a bit of a design dilemma with one of my projects. I have a class that represents a switch (physical switch that is). It contains information about the switch such as system description, uptime, firmware versions, etc.
I want to have a list of these switches represented by a number of divs. When programming in PHP, I would make a for loop and just loop through the list of the switches pulling the data into a template-esque string which would be echoed out.
That method isn't very dart-y. I could do it that way but it doesn't feel like the dart way. I would also rather input into the dom and add event handlers more dynamically. However my current solution adds a 'DivElement' to the switch class. I can then template the innerHTML for the div, and add an onClick event handler right into the constructor. Then as my 'manager' class loads the switches it can then append them to the dom with insertAdjacentElement('beforeend', aSwitch.element); to the correct spot.
I like this method for the most part as it allows me to provide the default display information directly in each object. But my problem is that having done at least a little ruby on rails (and other ruby mvc framework programming) I know having my model and my view coupled together like this is a big no no.
But for the small project I have I'm not sure if I really need to worry about adhering too strictly to that methodology.
So I'm at conflict with myself.

Wednesday, May 30, 2012

Long Overdue

Okay wow..... Uhm.. yeah. What can I say? I've been extremely lax in keeping content on here. For a period of time I got pulled into other projects. However recently I was able to work on a project which I was able to use dart, and not just my usual server side work, or internal server but something that would be customer facing. Albeit something very minimal and not actually 'interactive' for the customers who would see it. But still it was a great chance for me to make use of dart and it was nice doing something publicly visible. However due to the nature of it I was unable to share the code for it.

I've also pushed out the source to DartMud as I've not worked on that in some time. I may be able to get some more commenting and eventually some additional work on it, however at the time being it will probably be pretty stagnant for the next little while at least. If you're interested you can check out my git repository.

There have been many many chances to the dart editor, dart vm, et al. that I have no real possibility of listing them all here now. However work is progressing rapidly in all areas and the integrated build is seeing updates almost weekly. It's very exciting to see the changes and additions being added so frequently. And so far only the rare 'breaking change' has come through which requires significant updating to any code. One such change was an update to the way callbacks are assigned on sockets. But it was a minor effort to update DartMud to reflect those changes.

At the moment, my current tests have me playing with the webserving capabilities of Dart. I have just recently begun to play with writing my own server. For those looking to get into it a little faster however, there are a couple of nice projects already in place including an Apache mod_dart, to run dart server side scripts as you would run a PHP script right inside of Apache. Additionally there is Dart Start, which is a (Ruby) Sinatra inspired dart server. In particular Start allows for simple routing and parameter passing as popularized by Ruby On Rails. So by all means check them out! In the mean time I'll continue playing with my server and let you know as things progress.

Thursday, March 8, 2012

Darting here and there

So another Dart Editor update, now at Build 5104, get it here!. I love how quickly the dart integrated builds have been coming lately. This new version does away with the old 'Libraries' view panel on the left side (by default) and instead implements a Files view. Instead of opening a project you now open the folder containing your project. All of your .dart files are loaded into that. I wasn't sure about it at first, as it is a changes in how it would work previously but already I'm seeing the benefits of it. It does help to encourage a Good folder/subfolder layout, which I was already comfortable with anyways.

I've seen a few people report some difficulties loading their existing projects, however I can't really comment on that as I have not encountered those issues myself. This version did correct the mass of errors I was receiving in the previous version regarding variables hiding other variables or methods. However it did introduce a couple of new ones.

First, this version introduced the changes to the dart:io library, changing all eventHandlers over to be in the form of onEvent, and one-shot methods (such as File.exists) now take the callback function as an argument, as opposed to having to specify an 'existsHandler'. As such I had to go through my code and made updates to the Sockets and Files to properly reflect the changes to the library.

Secondly, I ran into an issue where any print statements, within a class, would generate an error or warning that "print" is not a method in , where ClassName is whatever class happened to contain the print statement. This post in the Dart Group provided an easy, temporary fix, that is to simply import 'dart:builtin' where required. A simple fix and helped to clean up the errors there so I could focus on my own errors that I had to worry about.

I notice that while the IDE and SDK were updated to Build 5104, the Dartium Build remains at 5070. At this time I am still unable to get the Dartium builds to run on my machine due to a version problem with the shared libraries. I receive the following error:

error while loading shared libraries: libgconf-2.so.4: wrong ELF class: ELFCLASS64

I believe this error is related to the fact that I'm running a 64-bit OS, but it's trying to load 32-bit build. This may also have something to do with my early ventures in trying to build DartVM, IDE, and Dartium myself and installing the extra libraries, etc, which may have conflicted with what Dartium is trying to load. In fact, now that I think of it, I should run a good apt-get autoclean and autoremove regardless. I don't believe it will fix it, but certainly clean up my system a little at least. Now I've not been too worried about this as my current project doesn't use or require any client-side work, but eventually it might be interesting to have a working copy of Dartium for when I start working on some client side projects. Hopefully the 64-Bit builds of Dartium will be available by then.

Monday, March 5, 2012

Dart Mud... Progress 2

So I decided it's time for another progress report on my Dart based MUD. This project has be a lot of fun, and giving me experience with the dart:io libraries including Files, ServerSockets, and Sockets. Before I get into too much, I will mention that there is a new Integrated Dart Build available. Version 4760 (though SDK appears to be build number 4759). You can find your download here. Since using this build I have been getting errors and warnings when using the dart:io library. However it doesn't prevent my project from running properly. Just distracting thinking I have an error when I don't.

To follow up on my previous post, I have begun using git locally to archive changes and keep a bare-bones changelog system. Already I see this being helpful in keeping track of what I have changed or done, and additionally, in being able to revert changes easily. Once I clean up some of the code and add a plethora of comments, I may pop the project up onto Github as well.

My User Object now allows for the creation of a new character, automatic saving of a user and loading user (and password) from a save file. To save character information I'm currently placing the information I want saved into a map, and using saving it as a JSON object. In the future I can see some issues I may need to work out, but since I haven't decided on how things such as Objects, equipment etc will be implemented yet I don't know yet how much of an issue they will be.

As part of adding to the User object, I decided to create a separate Login object as well which will handle the accepting of username/password and loading the character and creating a new User object from the loaded information. Additionally the Login object also handles creating a new account, posing the various questions (username, password, password confirmation etc), then creating a new User object based off of the data provided. This way a full User object isn't created until credentials have been verified, and also prevents User from showing up in the user list, or receiving broadcast messages etc before they have completed the Login process.

As part of the work to separate the Login class from the User class, I also created a separate 'Connection' class as a wrapper over top of the raw sockets. Primarily this just creates a couple of convenience functions over the Socket for write, writeLine, readLine, set the lineHandler and close the Socket. I made this its own library, so it is imported into the Server which creates the initial socket and then wraps the Connection around it, and then hands it off to the mudlib (which is its own library). The mudlib also imports the Connection class. The mudlib then passes the Connection off to a new Login object which uses that to communicate to the user (again as opposed to the raw socket). The connection object is then passed off to the newly created User object once it is created. User object adds a couple more convenience functions as well but mostly works with the Connection object as well.

I've added a couple more commands as well. Now able to 'say' to the local room, change the default prompt (which does save to the User file), and of course the always abused 'emote' command. Additionally I've got a good start on a simple line editor (and a simple command wrapper for it to see the results). The Editor is a separate object which will take over the Input/Output streams of a socket from the user. It does not remove the user itself, nor does it take the user's connection object. Rather it just updates the Connection object to use the Editor's lineHandler.

The editor has two modes, Command mode and input put. By default you start in command mode, from which you can either insert or append which will put you into the input mode. To exit the input mode, one just needs type a period (.) on a blank line. The editor works similarly to 'ed' but a little prettier. (For instance a prompt of ': ' in command mode and prompt of '~ ' in input mode). Currently implemented commands in the editor: a - append, i - insert, q - quit, h - help, p - print line, d - delete line. In the future some commands such as p and d will accept a range argument as well however this is yet not implemented. There is no 'save', if you quit it will return whatever is in the buffer.

The editor is called by the User object. The User object in turn is called by some other command or object (most likely a command which will do something with the output). To start the edit the User object has startEdit method called on it with a callback function as an argument. Once the editor finishes it calls the method doneEdit in the User object which resets the proper line handlers, and then calls the previous callback function with the String returned from the Editor.

When I first started working with the Editor I thought the obvious solution to use it would be a StringBuffer. However after only a few minutes of implementing it with the StringBuffer I found it lacked much of the basic functionality I needed, such as getting a specific line from the buffer, or removing a line from the buffer. I also can only add to the end of the Buffer and not to any particular point in the buffer. So that didn't last long at all.
When I looked at the StringBufferImpl class in the library, I saw that it was nothing more than a List of Strings. So I decided to do the same. So I created two List of strings. One for the full Buffer, and one for a temporary buffer. The temporary buffer is used in input/edit mode. Upon leaving input mode back to command mode then the temporary buffer is inserted into the full buffer.
To accomplish this, I originally tried using List#setRange. However I quickly discovered that wouldn't work as it would just overwrite the range, as opposed to inserting at that point. Additionally if the temporary buffer would exceed the length of full buffer, then it would throw an exception. Even though the list is an extendable list. So I tried List#insertRange, and that expanded the List as required, but it will only initialize the new range to the same value. You can't insert the range with with list as the new values. So it required first using insertRange to add the space for the temporary list, then setRange to change those values to be the strings in the temporary buffer.

Another area of interest is that I have implemented a RoomManager. Eventually the RoomManager will be expanded to have time outs so once a room has gone 'stale' (no activity in it for x number of minutes) it will reset the room. And, if still not used after y number of minutes, the object will be unreferenced for the GC to clean up as it will. The first part of this however, was trying to to determine how I can efficiently 'dynamically' load the rooms when someone tries to access them, or alternatively reference an already loaded room. Since I can't use eval to load a file at this point, the code has to be loaded on start up.
So I created two maps, each map has a key of a room identifier. One map holds the rooms themselves if they are loaded. The other, roomFuncs holds functions which create the room. Rooms are added by calling the add method on the RoomManager, which takes a callback as an argument. The add method then runs the call back to create the room. It gets the room's unique identifier to use as the key. Then it stores the callback in the roomFuncs map. Then when it comes time to access the room, we call the method putIfAbsent method on the room map, passing our roomId and a reference to roomFuncs[roomId] which returns the callback to create the room if the object is not already loaded. The putIfAbsent is a nice little method, and quite handy for this.

Well that's about all for now anyways. I must say I'm having a blast writing this simple mud, and while I have a long way to go for a full featured mud, it is virtually usable at this point. Dart is a lot of fun!

Monday, February 27, 2012

Dart MUD... Progress 1

So before I get started, I just want to put out there that the latest integration build of DartEditor has been released, and you should pick it up here. This build contains the latest IDE, the SDK and now Dartium as well! For those of you running 64-bit systems, it is a 32-bit build of Chromium so you may encounter some library errors if you have not installed the extra components you need.

So now that that news is out of the way.. a little progress report on my Dart MUD. (I may need to come up with a better development name, as it conflicts with the already existing MUD: Dartmud.com) So far I have a minimal server, from which I've managed to remove most unnecessary code from and make the mudlib independent of the server. I have a generic MudLib object which handles most interactions between server and specific mudlib components. A User object which handles the client connections and various user properties (username, passwords, etc). However I'm not completely happy having the socket implementation directly part of the User object, and may break down into a connection object which the User class will either have it as a property, or may inherit from (just because someone connects, doesn't mean it will result in a User on the system).

After some playing around with a static class which contained the various commands a player can execute, I decided to instead create a small class, and each command is an instance of the class. All of which are managed by a CommandDaemon/Command Manager. I can see this allowing for more flexibility in adding commands globally and perhaps even in just specific rooms or objects. On the note of Rooms and GameObjects, I have classes for these also implemented, as well as a 'container' interface and a factory class for it. Users and Rooms both currently extend the factory class for the container.

At this point, I've added a few 'commands', including the exit and shutdown commands from the EchoServer (though now setup to be used with the Command Manager I have implemented). I've also added a basic 'look', 'broadcast' and 'help' command, and am in the process of fleshing out these respective commands so they properly handle any arguments sent to them (broadcast works to notify all users, regardless of if they are in the same room as the person issuing the commands.

I still have so much to do. Currently when connecting you are prompted for a username/password to log in. However you can enter anything an be granted access with the username you enter. I need to be able to create a new user, to save the user, and to load them when logging in. Also I have a very basic room, but only the one. I still have to create more rooms and implement travel commands to move between rooms. To say nothing of the other normal things you would expect on a mud including equipment, objects, money, combat, etc etc etc.

While I still have a very long way to go to make a basic mud, I'm quite pleased with the progress I have been making towards that end. Something I may want to look towards as well is some type of 'reload' or 'refresh' command, as I have to shutdown the server and restart it after each change I make. I'll also need to work on a memory management daemon of some kind too, so that once the mud gets to a decent size, objects will only be loaded/created when accessed, and after a period of time, removed if not used or near an active player.

One of these days I'm going to make an effort to learn git/git hub too.

Thursday, February 23, 2012

Featureless Sockets

Okay, so the title is a bit of a stretch. Dart Sockets are far from featureless. As some of you may or may not know, I've decided to take a segue in my EchoServer towards working on a basic MUD and MUDLib written in Dart. It will be far from full featured, and far from fully functional but it will be the basis and a nice little start.

Within a few minutes of converting the EchoServer to be the basis of the MUD driver, I've already run into an issue of a missing feature with Sockets in Dart. I'm unable to get the host of an incoming connection. That is, I can't find out who is connecting to me. While it's a trivial matter for a MUD, or many other services, one would expect such functionality for various uses including HTTP server logging, etc.

After digging through the bleeding edge to see if it may have been recently included but just not yet updated in the API, I still can't find any reference to such properties. So as such, I've created a bug report over in the Dart issue tracker. If you're interested, or want to star the report you can view it here at: Issue 1819

As I progress with the Dart core and MUDLib I'm sure I'll find some additional bugs to report, or just missing features I can think could be added. Additionally I'll keep progress reports available on here and eventually release the source on GitHub or something similar.

Tuesday, February 21, 2012

Serving Sockets... The Salad

I haven't had the opportunity to do much with Dart lately, due to scheduling. However this afternoon I had a little chance to write some more. I decided that I wanted to modify the EchoServer to maintain the connection and close the connection only when receiving a specific command. I also wanted to add a command to shutdown the server itself completely. In order to properly accommodate this, I needed to refactor the server code a little. I wrapped the ServerSocket in a manager class:

#import('dart:io');

class ServerManager {
  ServerSocket _listenServer;
  
  ServerManager() {
    _listenServer = new ServerSocket("127.0.0.1", 5700, 0);
    
    _listenServer.connectionHandler = this._handleConn;
  }

  void _handleConn(Socket conn) {
    StringInputStream clientIn = new StringInputStream(conn.inputStream);
    
    clientIn.lineHandler = () {
      String input = clientIn.readLine();
      print("Received: $input");
      if(input.toLowerCase() == 'stop') {
        String cls = "** Stopping Server. Closing connection **\n";
        conn.writeList(cls.charCodes(), 0, cls.length);
        conn.close();
        _listenServer.close();
        print("** Stopping Server! **");
      } else if(input.toLowerCase() == 'exit') {
        String cls = "** Closing connection to client **\n";
        conn.writeList(cls.charCodes(), 0, cls.length);
        conn.close();
        print("** Closing connection to client. **");
      } else {
        String output = "${input.toUpperCase()}\n";
        conn.writeList(output.charCodes(), 0, output.length);
        print("Sent: $output");
      }
    };
    
  }
}

void main() {
  ServerManager sMan = new ServerManager();
 
}

So as you can see I made a few changes from my original EchoServer. As mentioned above I wrapped the server in a manager class, this enables me to easily close the server socket without using a global variable. In addition I added a couple clauses to check for the 'stop' or 'exit' commands which will stop the server or just close the client connection respectively. And finally I stopped pulling the output stream of the sockets directly, and instead use the writeList methods directly on the socket itself. I wasn't gaining any real benefit by creating an additional variable for the socket's OutputStream, so I just dropped it altogether.

Now as is, the above will run and accept connections and echo any new lines until the stop or exit commands are received. If the exit command is received, then the server will close the connection to that socket. If stop is received it will close the connection to that socket and then tell the server to close. However because of the event driven nature of the server, the Sockets and ServerSockets are not blocking. That is, even without adding any additional threads (Isolates), we can accept connections from multiple sources. If you open up multiple telnet connections to the host, you can see how you can send data and receive responses on each connection independent of the other.

But this also leaves us with a small issue. If we tell the server to stop from one telnet session while the other is still active.. the server will accept the stop command, and it will schedule the ServerSocket to be stopped, but not until the other socket has been closed. Try it out and you will see that the connection in which we issue the stop command is disconnected, and the console will indicate that the server is stopping. But the other telnet session will remain active until we issue an exit or stop command. Only once the 2nd session is closed will the server stop. And if for some reason the other session does not terminate properly (for instance connection drops or the telnet application is closed before issuing an exit/stop command) then the server will hang, not accepting new connections but not terminating either (assuming eventually the socket will time out but potentially not since I do not have those error handlers in place either).

This may be the desired situation with some servers to shut them down gracefully for instance, however in our EchoServer we want it to shut down immediately if it receives the stop command. So we'll need to keep a list of active connections and iterate through them and close each one, then stop the server. So I ended up with the following:

#import('dart:io');

class ServerManager {
  ServerSocket _listenServer;
  List _socketList;
  
  ServerManager() {
    _socketList = new List();
    _listenServer = new ServerSocket("127.0.0.1", 5700, 0);
    
    _listenServer.connectionHandler = this._handleConn;
  }
  
  void sendStops() {
    List cls = "** Server received stop request. Closing connection to client **\n".charCodes();
    
    while(!_socketList.isEmpty()) {
      Socket conn = _socketList.removeLast();
      conn.writeList(cls, 0, cls.length);
      conn.close();
    }
  }
  
  void _handleConn(Socket conn) {
    _socketList.add(conn);
    StringInputStream clientIn = new StringInputStream(conn.inputStream);
    
    clientIn.lineHandler = () {
      String input = clientIn.readLine();
      print("Received: $input");
      
      if(input.toLowerCase() == 'stop') {
        sendStops();
        _listenServer.close();
        print("** Stopping Server! **");
      } else if(input.toLowerCase() == 'exit') {
        String cls = "** Closing connection to client **\n";
        conn.writeList(cls.charCodes(), 0, cls.length);
        int sockInd = _socketList.indexOf(conn);
        _socketList.removeRange(sockInd, 1);
        conn.close();
        print("** Closing connection to client: $sockInd **");
      } else {
        String output = "${input.toUpperCase()}\n";
        conn.writeList(output.charCodes(), 0, output.length);
        print("Sent: $output");
      }
    };
    
  }
}

void main() {
  ServerManager sMan = new ServerManager();
 
}

As you can see I also added a method sendStops just to iterate through all the sockets, popping them out of list and sending them the stop notice and disconnecting them. I made this separate from the actual stopping of the server in case it should ever be required for any other reason as well. Initially I tried using a Set to hold just unique connections, and provide easier way of removing elements however I found out that there's an issue with Set's in that any values stored in a set must implement Hashable. This wasn't added in the API documentation and it was only after a little digging through the DartBug page and Newsgroup that I found this is 'expected' behaviour. As such, I had to use the list. For a specific 'exit' command I have to get the index of the value and remove it from the list with removeRange with a size of 1 element. I also setup the broadcast message directly to a List of Int's immediately just to avoid having to convert it multiple times as I iterate through the connections. While still missing any error handling, etc. I'm rather pleased with how the server is progressing and in some ways it conjures up images of the old school MUD's. Maybe a project to play with?