Showing posts with label AngularJS. Show all posts
Showing posts with label AngularJS. Show all posts

Sunday, September 21, 2014

Long Time No Post

Wow, it's been a while since I've posted anything. I have been keeping busy though. I haven't started on any major new projects, but I've made some pretty big changes to some of my existing projects so I might as well write something about them.

Firstly, the thing that's been taking up most of my spare programming time has been a rewrite of Scrobble Along. I decided to rewrite it mainly because the old code was written in an old version of TypeScript in Visual Studio, and after I installed the new TypeScript compiler my Visual Studio code stopped compiling. Rather than try to port over the TypeScript I started making hotfixes to the generated JavaScript and everything got really messy really quickly. I also really didn't like that the scraping part which gets all the tracks that are playing on the various radio stations was mixed in with the frontend website code. Also all programmers love starting a project from scratch, and I was pretty keen to work on another project that could use AngularJS. Now I have two separate codebases, the scraper runs on a Linode server I have, and it just loads all the stations about every 30 seconds and grabs the tracks from their various HTML and JSON sources, then scrobbles the tracks to the station's profile and to anyone who is scrobbling along. The frontend website is running on Heroku, and all it does is load information about the stations, and adds record to my database when someone starts or stops scrobbling along. It's much saner code now and I still really love AngularJS so I'm much happier about the project now. I did have to make one other major change, and that was to make the website pull the latest track details from my database rather than trying to load it from the last.fm API. For some reason, when I re-wrote the code it started taking a whole lot longer to load all the station details from last.fm, so it was taking a good 30 seconds for everything to show up. Right now it's loading all profile images, recent tracks, etc from my database so it's a whole lot faster than it used to be. I've got the code on two separate github repos, but I made a simple repo that has both of them as submodules here, so feel free to check out the code for more details.

The second thing I've been spending some time on has been updates to Trashbot. I've been experimenting with ways that I can try to combat bots that are just taking everything from as soon as it is dumped in. My plan was to limit the number of trades for each account to taking something like 10 items per day, but that would be impossible until I was able to quickly look up the trade details. As a first step I wanted to make a record of all the details available in MongoDB, under 3 tables. The first one would be a summary of each user, containing the total number of trade requests, items taken and donated, friend requests etc. The second one would be granular details for each trade, including the item, time, user, etc. The third one would be a record of the number of trades each user had made in each day and how many items they took and gave. Once that was set up I was going to look up the daily trades before accepting anything, and if a user had already taken too much I was going to make the bot refuse the trade. I've got the details being saved to MongoDB now, but I'm 90% sure I'm not actually going to refuse trades, as when I look at the details, there really are not many individuals who are taking the majority of the items. I think just occasionally looking though the details and banning a few people is the best option, any systematic method I come up with will just end up as an arms race against any "takerbots" that are out there. It was an interesting process to get all the details to be recorded though. I ended up writing a simple REST server that would update MongoDB when various POST requests were sent to it, e.g. I have something like /trade/userid/tradeid/itemid/taken which will update all the tables with one more trade item taken by a particular user on a particular day. Doing it this way meant that I was able to record the trade from both the bot which is accepting trade requests, and the CasperJS script that is accepting the trade offers. Again, the code is up here on GitHub if anyone is interested.

The final thing I'll mention was a relatively small weekend project I did for a battle created on the /r/webdevbattles subreddit. The challenge was to build an elevator simulation, and it piqued my interest because it was similar to a job interview question I got which I did not to very well on. Most of the people competing were focusing on the "frontend" part of the problem, e.g. by making CSS to show elevators moving up and down, but I wanted to focus more on the "engine" part of the problem, as that was what the interview question was about. I ended up writing a simulation that represented passengers and elevators as individual state machines, which would operate independently. The passengers waited on a floor, requested their destination, then waited around constantly checking for an open elevator that was going in the right direction, and at that point they would get on and wait for the doors to open on their destination floor before getting out. The elevators had a set of target floors and they just moved to those floors and opened their doors, waited until no-one had entered for a while, then headed to their next floor and opened their doors, etc. A central "brain" was in charge of reacting to floor requests from passengers and assigning those floors to one of the several elevators. I think it was a good idea, but I was limiting myself to a weekend's worth of work, so it's not really working 100% right now and elevators have a habit of bouncing between floors indefinitely and never reaching their target floors. I'm pretty sure the elevators need some sort of floor queue rather than just using a set of floors that they need to end up on at some point, but I'm not really planning to test that theory any time soon. Once again, I used AngularJS to visualize the engine data, and was very impressed with what I was able to get working in a pretty short amount of time. The code is up here.

And that's it! I'm not quite sure what I'm going to work on next, it's been a while since I've been in a situation where there isn't a project I know I "should" be working on, so I think I'll have to think up something new.

Thursday, December 5, 2013

Following Along with the WebStorm 7 Demonstration Video

As I mentioned in my last post, I was thinking about starting a new project using Node.js, and this video for the new features in WebStorm 7.0 caught my eye:



It looks like a very slick IDE and I was looking forward to trying it out, but I ran into a whole lot of little problems when I tried to follow along. I'm pretty sure I've figured most of them out now, so I thought I'd try to go through the entire video and explain how to follow along with it.

First things first - making Roster.ts (0:00 - 0:30). This demonstrates the automatic compilation of TypeScript, so you'll first need to make sure TypeScript is properly set up. The file is created using the alt-insert shortcut, which lets you type in the type of file to create followed by the name of the file. When you first create a TypeScript file, you'll get a prompt about adding a File Watcher, which is what will automatically compile your TypeScript into JavaScript (along with a map file so you can debug through the TypeScript code). The first problem I encountered was that I had installed TypeScript 0.8 via an executable a while ago, so even though I installed the latest version (0.9.1-1) using npm, the file watcher was using the 0.8 version that was stored in a different location. Make sure you check that the watcher is pointing to the right file by running the compiler with the -v flag which will print out the version number. The second problem I encountered was that I kept getting the error "error TS5037: Cannot compile external modules unless the '--module' flag is provided." After a bit of module confusion as I mentioned in my last post, I realized that since we are writing Node.js code, we should specify that tsc should use the CommonJS module system, which you can do by editing the file watcher and adding --module "commonjs" to the arguments. With that confusing diversion dealt with, I was able to write up the Roster.ts file with the autocomplete working as it shows in the video. One small comment is that in the video they use a capital-cased String rather than a lower-case string, but that is easily changed.

Next is server.ts (0:30 - 1:43). This file uses some Node.js packages, so there are two "hidden" things to set up here. Firstly, you'll need to make a package.json file that sets up dependencies for the app. This example only uses express and cors, and we don't need to be strict about the version, so you can use the following file:
{
    "name": "application-name",
    "version": "0.0.1",
    "dependencies": { "express": "*", "cors": "*" }
}


Now you just need to run "npm install" from your project directory to pull in the required libraries. There are a few other ways to do this, you could just npm install the packages individually or use the Node.js and NPM settings, but keeping it in the package.json file means that we will be able to install the project in other places easily.

The second piece of setup is DefinitelyTyped, which is a set of files that contains the definitions for many different npm packages, so that we can compilate and use code completion for those packages. This can be downloaded or added as a git submodule using their github repo, or we can pull in individual definitions by going to the JavaScript -> Library settings and Downloading from the TypeScript community stubs section. I prefer to use a git submodule so that it's easy to update the definitions. I do like the idea of the community stubs, but as far as I can tell you need to copy and paste the file (renaming it in the process) into your projects main directory structure before you can use them properly, and that's too much work for me.

With this setup done, the creation of the server.ts file goes about as well as it shows in the video but there are some hidden tricks. I'm not entirely sure, but I think the magic that translates "ref" into "/// <reference path=""/>" is a custom Live Template, which I was able to add by making "ref" an abbreviation for "/// <reference path="$END$"/>". The extra "find relative references" magic can be conjured by using ctrl-space (possibly twice), which will bring up the list of relevant files. The next trick which automatically inserts a variable for "new jb.Roster()" is called Extract Variable, and can be accessed using ctrl-alt-v. One thing I couldn't get working was the explicit typing for ExpressApp/ExpressServerRequest etc., which I guess has had a change in name since the video was made. The IDE is smart enough to infer the type from the context so it's not a big deal. And for server.ts's final trick ... I guess it's some more Live Templates that are converting "get!" and "post!" to some pre-built function skeletons.

"Debug Node with ease" (1:43 - 1:58) really is as easy as they show (as long as you have the right npm packages installed), but "Test REST services" (1:58 - 2:30) is a bit trickier. The first thing to note is the "Enter action or option name" dialog which you can summon using ctrl-shift-a and use to find just about anything - in this case "test rest" opens up the REST client. Before it works as shown in the video you'll probably need to change the port and path and ensure that you've added the "content-type: application/json" header. Once that is sorted out though, take some time to play around with the pain-free TypeScript debugging, it really is pretty amazing when you think about it.

Now we get to the client side, the file app.ts starts out as a pretty standard AngularJS app, written with the assistance of the auto-completion and templates we've seen before (2:30 - 3:25). AngularJS is an awesome framework for client-side code but I'm not going to go into it here, if you want more information check out their website. The only note I have for this section is that my version of app.ts had a compilation error "The property 'message' does not exist on value of type 'AppCtrl'", which was easily fixed by adding message as a public variable on the class (public message:string;).

The next file that is created is a HTML file, but one that is created using "Emmet live templates" (3:25 - 3:40). This is something I have never seen before, but it looks like a bunch of shortcuts that expand into full HTML, nifty! It looks like it takes the best part of Jade - not needing to write HTML - with the added benefit of producing HTML rather than the sometimes confusing Jade markup. These are configured as Live Templates, so the usage and configuration is the same as the "ref" template we saw earlier. Find relative references also works inside script tags, so that is a few more keystrokes you can save here. But wait, what is this bower_components folder and where does it come from? This is another technology I've never seen before, but my minimal research leads me to believe that it is basically npm but for client side libraries. You create a bower.json file, specify the libraries you want to install, then run "bower install" to pull the files into your project (after installing it using "npm install -g bower"). This example only uses angular and angular-resource, so we can use the following (strangely familiar) file:
{
    "name": "application-name-client",
    "version": "0.0.1",
    "dependencies": { "angular": "*", "angular-resource": "*" }
}


Now the files can be found, and we can start putting some AngularJS into the HTML (3:40 - 3:55). As hinted at in the video, there is auto-complete for Angular directives, but it requires a plugin. To install it, go to the Plugins section of the settings, browse the repositories, and search for and install the AngularJS plugin. After restarting, the auto-completion should be working as shown in the video. I'm not sure what is converting "bi" to "{{}}" but I'm just going to assume its another custom template and move on.

The next part demonstrates how to start a debugger on the client as well as the server (3:55 - 4:25), which is pretty easy to follow along with but you might need to install the ExtensionJetBrains IDE Support Chrome extension. After a small change, we realize that the app dependencies aren't loaded correctly, so there is a bit of a detour to go an install that package, which is again easy to follow (4:25 - 4:45).

Next is some demonstrations on how to use browserify, which is yet again something I had to look up. A high level outline is that it looks like something that lets us write CommonJS/Node.js style require/export code in client-side code. Browserify can parse this code and use it to generate a bundled javascript file that can be included in the html. I'm not sure why this would be preferred over compiling TypeScript using the AMD module and using RequireJS to load the dependencies, but it does look pretty easy. The video shows a few different ways to call browserify (4:45 - 5:40), you can do it by running an interative terminal (alt-minus), or apparently through a "simpler command window", but I couldn't find that. You can also set up a file watcher that will detect when a change is made to app.js and automatically run browserify on it, similar to how JavaScript is created whenever you modify a TypeScript file. This is also easy to follow as long as you pause the video quite a bit so you can actually see what's being clicked on. With the bundle generated, we can now run and inspect our code.

The rest of the video is some code that you'll need to know a bit about AngularJS to understand, but it all works as shown (5:40 - 6:50), and that pretty much wraps up the video! Two things I still don't understand are how to get the camel-case expansion to work (e.g. RR => RosterResource), and what that "jump-to" shortcut is or what it's doing, but I'm sure I'll figure that out eventually.

Now to work on a real project in WebStorm!

Sunday, August 4, 2013

Online Steam Group Chat App

I've just finished off another project, so it's time for another blog post. This time my main goal was to get some experience with AngularJS, something I have been reading a lot about which seems like a pretty cool bit of tech. When I was trying to think of something to make, I remembered that in the early days of my Steam chat bot, I made a little website that would allow people to send a message to the chat room through the bot. It was just a bit of fun at the time but I thought I could expand on that and make a web interface into a group chat room, something that Steam has not yet provided for some reason, even though you can do user-to-user chat through their site. This would also give me an opportunity to use Socket.IO, something I'd used previously but not really well.

This took me a bit longer than I was expecting for a "simple AngularJS project" but at the end of the project I've learnt a lot and I've made a nice website that at least a few people should find useful. It looks and acts pretty much exactly like the Steam client which I'm pretty happy about, and thanks to Foundation it handles mobile/tablet resolutions quite nicely. I've put the code up over at GitHub, it should be fairly easy to set up for any Steam group so go and have a look if you're interested. Here is a blurry view of what it ended up looking like on the desktop (if the screen gets small enough, the chat member section gets hidden and you can click a button to switch between the chat view and the member view):



Instead of going into implementation details I'll just quickly go through the different technologies I used and explain them one by one.

The first thing I should mention is that I again made use of the excellent node-steam node library, which is what allowed me to mirror the chat messages and send messages to the chat room. I had considered using my chat bot, but in the end I really didn't need any of the features it provided and I decided to just use the vanilla library. There isn't much to go into for my usage of the library, I basically just used the provided functions to get and send messages, and to find out when user statuses changed so that I could update the list of users in the chat room.

For client-side code I used AngularJS, which as I mentioned was the main reason for starting work on this project. I was very impressed with Angular, whenever anything changed on the Steam side (a new message, a user joined or left, or a user's state changed), all I needed to do was update my model and the UI was magically updated. I also really liked the separation of controller/filter/directive/services. Although I didn't really make use of any services (except a pre-made Socket.IO one), it was great to be able to make a filter that built a URL for a Steam profile image given a set of hex numbers, or a directive that represented the display of a users information, and have that completely separated out from my main app code so I could just concentrate on the task at hand. I feel like I still have a lot to learn about Angular, and I'm pretty sure a lot of what I did wasn't the "correct" Angular way of doing things, but even just scratching the surface of what Angular has to offer has been very interesting.

For server-side code I used the express framework, which I've used for a few different projects before. Since I was working on a single-page app without too much back-end logic (besides things I'll mention separately), there isn't too much to go into with my usage of express. One thing I'll say about the server-side implementation in general is that I really should have used TypeScript. The reason I didn't was because I wanted to use plain JavaScript for the front-end, and I thought it might get a bit confusing to switch between the two. It was good to get a bit more experience with JavaScript, but I really feel like some sort of type checking is crucial to coding, and TypeScript would have been a good safety net to use.

The communication between server and client was handled mainly by Socket.IO. When someone visits the site, they have a socket set up for them which goes through some authentication. To be able to chat they need to be signed in through Steam, so the Socket.IO authentication has access to the user's Steam ID. I use this to make sure that the user should be able to see the chat room, and if they are I set up a bunch of socket listeners so that I can notify the client of any chat room changes, or other state changes such as notifications that the chat has been muted or that the proxy user has disconnected for some reason. One thing I noticed was that a lot of this code was just boilerplate, since I had a model of sorts on the server side and an Angular model on the client side, and most of the Socket.IO code was used to synchronize these two models. I was going to try to think of a way to build some sort of system that would automatically listen for any changes on the server side and send that down to the client side via sockets, but it was looking like it was going to take too much time. Now that I've finished the project I think I may revisit that, as it seems like something that would be very useful for anyone making an Angular app that needs to be notified of state changes from the server side.

For the website layout I decided to use Foundation. I was originally going to use Bootstrap, but I wasn't going to use any of their styles and I had heard that Foundation was better as a "clean slate" solution. Also admittedly I just read about Foundation and it looked like something new and interesting. In the end I'm pretty happy with the way it worked out, it is a bit simpler than Bootstrap and it had a few features that came in very handy, particularly Top Bar which handled my menu needs really well, and the Reveal modal dialog which was great to use as a state messaging system since I needed something that would block the normal use of the site and provide a message in a very obvious way. One thing I wasn't quite able to work out was a non-hacky way of providing a mobile and full-screen interface to the chat room. For normal website usage I wanted the chat room and member details to be shown side-by-side and for mobile use I wanted the user to be able to switch between the two by pressing a button. In the end I solved this by having two completely separate divs, one that is shown for desktop use and one that is shown for mobile use. This wasn't too bad since I made use of Angular scope and directives to separate out code that would otherwise have been duplicated, but I could tell that there must be a better way of doing it. Of course, this isn't a problem with Foundation, just my lack of experience with it.

One final thing I'll mention is the authentication solution I came up with. This is one thing that went through a few different iterations but I think the solution I ended up with works really well. The first part of authentication was simple enough, Steam provides an Open ID login library in their Web API, so all I needed to do was use an Open ID node library and I could get access to a user's Steam ID without any risks. The second part of authentication was trying to figure out if a particular Steam ID should be able to see the chat room. I had originally thought of having a whitelist, so a user would have to request access and I'd have to go in look at the user's profile page and approve if it looked OK, but I decided that was too much work. After this I thought I'd just make it a rule that a user would have to be in the chat room the first time they used the site, and that would automatically add them to the whitelist so they'd be able to log in without being in chat from then on, but that seemed a bit too confusing for users. After a bit more digging around in Steam's web API, I found out that they provided a way to see the groups a particular steam ID belongs to, so I decided to just use that. Any time a user logs in, I check to make sure they are part of the group, and allow them access if they are. This is completely transparent to the users and it keeps out randoms from the site. The only problem is that someone can be kicked/banned from the chat room and they'd still be able to use the site, but that rarely if ever happens in the steam group I'm using the site for so it's not a big concern.

So that's another project and rambling blog post done. Hope either of them come in handy for someone else at some point!