MLDonkey Downloads Import Module Development
Development in progress.
Tuesday, February 28, 2006
Reconstructing object hierarchies in CGComm
Did a nice 12-hour devsession, and made nice progress in several areas. Unfortunately I didn't get to global searching yet - guess that'll be next dev-session's topic. Anyway, here's the list of changes tonight:
- No longer creates ed2k userhash twice on first startup
- Compilation with Mingw compiler should be fixed (there's some mess with if/how stat64 is defined)
- SSocket class is now Trackable, clearing up few speed-signal-related crashes (a member function of SSocket is often connected to other speed-displaying signals)
- Fixed three (!) debug messages in PartData class that had invalid number of arguments and caused unhandled exception - but only when deleting temp files failed.
- No longer scans same shared folder twice (e.g. if folder is already shared, it won't be re-scanned at a later time). This has nothing to do with 'rescan' concept, which will be a separate function altogether.
- Supports more than 64 open connections on Windows (up to 512 now)
- Only outgoing connections will count towards connections-per-sec value; this should reduce the false low-id issues with ed2k module.
- Chunk class is also now Trackable, to avoid crashes when PartData is canceled while chunk hash job is in progress.
- Simpler and more robust SharedFile::read() syncronization mechanism that hopefully clears up the torrent-completition-crashes once and for all.
- CGComm protocol is now capable of re-creating PartData and SharedFile object hierarchies at the other side of the protocol (e.g. torrents with >1 files).
- GUI displays torrents in a treeview - click on a + sign to see the sub-files of the torrent. As before, each sub-file of the torrent can be paused, stopped, resumed and canceled separately, providing maximum flexibility.
- Dynamic module-based upload-speed scaling, based on how "useful" the module has been to us; a module which accounts for 80% of all downloaded data will receive 80% of upload slots.. This is Mode One of the three planned upload-scheduling modes - automatic and user-defined (percentages) and user-defined (priorities). The latter ones will be implemented some time in the future. Note that these limits are "soft", merely hints to the module / upload-slot opening code. Hard limits do not make sense in this scenario.
- Contrary to popular belief, 16 bits is not enough for everyone. CGComm protocol packets are now sent using 32bit size field. If you were tinkering with the protocol, you need to update your code - there's no backwards compatibility kept at this phase of the protocol development. Anyway, the reason for this change was that DownloadList packet of 600 downloads (cpl big torrents) exceeded the 65kb limit of 16bit size parameter, and breaking the list into multiple packets just causes more problems.
- Torrent name is now included in tracker error messages as well.
Some 4-5 hours of the 12-hour session went to tracking the open connection issue on Windows. If you had used Hydranode on windows, you might have noticed hnshell freezing sometimes and other strange networking issues. After lengthy testing and research, I discovered that the moment connection count exceeded ~50 connections, UDP packets started failing in ed2k module. Further testing showed that networking everywhere in the app started behaving strangely when more than 50 connections were open. After more testing and surfing around, I finally discovered that by default, select() on Windows is limited to 64 sockets! This is one of the times where I really wish someone with Windows networking programming would hang around and tell me these things, heh. Anyway, the workaround is simple - define FD_SETSIZE to a value of your choosing (512 is max as far as I understand) before including sys/select.h and there you go.
So basically, what was happening until now with Hydranode on windows was that we only checked first 50 sockets always; since the ordering of the sockets is somewhat random, this caused HALF of the sockets to fail HALF of the time - enough to wonder why things are strange, but not enough to warrant deeper research. As the connection-count increased, the failure percentage increased as well, but those are rare cases when more than 100 sockets are open (well, until you start few torrents, anyway), so... UDP sockets displayed this issue more obviously, since UDP sockets are added to the select() socket descriptors listing after all other sockets have already been added, so the moment 64 TCP connections were reached, everything about UDP died.
PS: New binaries are available for Windows and Linux; source code now available in three formats by default (zip, gz and bz2).
Monday, February 27, 2006
Working on gfx & layouts
Progress with our designer on the icons and background images has been somewhat slow, but progress is being made. He estimates few more nights to complete the majority of the first iconset and background images (each page will have a light, transparent background image).
The Home page layout was discussed and decided that it will be google-style search page, with customizability options, such as displaying RSS feeds and more - similar to Google's "Personalized home page". Initially I plan to use Qt's own HTML-rendering capabilities, which are somewhat limited, but should be sufficient for this purpose. In long-term, we might have to load external HTML renderer (IE on win32, etc) if we want to display more advanced, dynamic content there (possibly promoting legal/free content there), somewhat similar to Windows Media Player's Media Guide or eMule Content Database. However, the latter is more of a long-term future plan, since we lack the resources to set that up in near future.
The zombie-client optimizations and other tweaks have had rather positive impact on overall speeds and stability of the speeds. Downloadsession averages are over 5 MB already, 5.35 MB in my current session, uploadsession averages at 4.74 MB. About 6 months ago it was around 2-3MB, and around 3-4 months ago it was around 4 MB, so it's a definate improvement. Downloadsession failure percentages have dropped as well, down to ~36% (from ~45%).
My current top priority topic is global and multiple searching capabilities - something that's boring, and somewhat tricky to implement, which are the reasons why I'v delayed it so long. But obviously it can't wait any longer, since it's essencial feature for the GUI to use.
Friday, February 24, 2006
Library page backend
Well, the title pretty much says it all. I wrote the core-side backend for shared files listing handling. The implementation was rather similar to that of downloadlist handling, so relativly easy. Since we didn't have per-file upload-speed calculation (like we have for downloads), and we didn't even store total uploaded amounts for files (ed2k module stores credits, but those are per client, not per file), I introduced those API changes as well. Both ed2k and bt modules support the new features as well.
Needs some tuning still - I'm not happy with how the location is displayed - will probably drop that altogether - but at least the protocol-side backend is in place. Btw, something of interest - SharedFile object has member pointers to both PartData (in case of temp file) and MetaData (which contains extended file information). While we cannot transport pointers directly to the GUI, I realized that I can simply use the object ID's (unique for each object) for the same purpose - we'll transmit two ID's with SharedFile object, and the gui can request the objects behind those ID's separately (if they'r not already known by libcgcomm). libcgcomm, on the other hand, will detect such links, and replace the ID's with actual object pointers in the GUI-side API. Soon we'll see how well this idea works in practice.
One annoying bug that had been bothering me quite a while was that sometimes, GUI would just crash for no apparent reason, and JIT debugging didn't even kick in. After quite some tracking, I discovered libcgcomm sometimes got confused during parsing and broke - and all subsequent parsing attempts naturally failed as well. Further tracking revealed that there was an unhandled exception thrown from somewhere, and it was never caught until it reached Qt code (and Qt doesn't use exceptions internally, so it was never caught there either). But the exception wasn't due to protocol incompatibilities between libcgcomm and cmod_cgcomm - as it turned out, the actual issue was that the parsing buffer was reset only once, right before the parsing loop; so if during parsing, two or more packets were discovered, the parser broke, and that only happened when either core or gui were overloaded and were unable to process the data fast enough.
Learning from the above, I added quite a lot of exception handlers on both core and gui-side parsers, to avoid further crashes and provide human-readable errors (well, developer-readable, anyhow) when things go wrong.
I made a second attempt at the "Home" page (as we now seem to be calling it) layouting, but didn't come up with anything show-worthy sadly. That page is pretty much the most complex page of the GUI, since there isn't a well-established standard on how to do it (and frankly, we don't even know WHAT it should do specifically).
Thursday, February 23, 2006
SVN back up
Since the SVN crashes started really getting on my nerves, I considered the option of manually upgrading it (debian stable has only 1.1.4, while newest is 1.3), but due to the dependancies, this could potentially cause more problems and break other things. So as an alternative, I temporarely shut down devcenter, to determine if trac is the cause for these crashes. So far, SVN has been up for few hours, so we'll see in few days if that truly was the cause.
I also checked in a bunch of changes - proper upload-pausing while completing file, some 'zombie-client' fixes and the libcgcomm-side sharedfiles listing protocol implementation (currently lacks core-side backend).
On the GUI / icons side, real life issues have made it impossible for me to meet up with our designer (for two evenings already) again to finish what we started; hopefully I have time tomorrow to do that.
Tuesday, February 21, 2006
The report of the memory leak with MSVC8 caused quite some interest in Boost.Dev list; DateTime library was patched to work around this bug, but numerous other libraries are also affected by this, notably lexical_cast and program_options. Since patching MSVC CRT requires rebuilding the DLL, it's easier / more convenient to patch Boost libraries instead for the time being, until Microsoft releases official update. Considering that Boost 1.34 is expected to be released within a month, hopefully all the issues will be cleared up by then.
I discovered an issue in Utils::getFileSize() method which reported wrong size on Windows when the file size exceeded 4gb. The issue was usage of stat() method, which uses 64bit offsets on Unix when _FILE_OFFSET_BITS is defined as 64, but was using 32bit offsets on Windows. The fix was to use _stat64 on Windows. This bug caused all Bittorrent downloads which included files of size >4gb to become auto-paused with message 'out of disk space'.
I have also been working on thread-safe version of SharedFile::read(). The issue there is that when completing file, the file is moved from temp to incoming, and read operations while moving is in progress, or after the moving has been finished, but SharedFile::m_location hasn't been updated yet, fail, causing the SharedFile object to be destroyed, which under some circumstances can lead to crashes in hncore/bt/files.cpp. The solution was to use boost::recursive_mutex::scoped_try_lock in SharedFile::read() (try-lock so as to not block the main thread), and scoped_lock in MoveWork::process to syncronize the operations and throw E_TRYAGAIN error from SharedFile::read() in this scenario. Plugins handle this exception and re-try reading from the file in a few seconds. However, since the code hasn't been fully tested yet, it's not in SVN (not that SVN would be up, anyhow).
Last night I spent about 6 hours with our designer, working on icons for the GUI. So far, the results are 5 black&white base shapes, onto which we hope to add some style and effects tonight.
The 'zombie' clients count reported by 'ed2k deadsource' command was somewhat off originally, displaying too large (up to 60%) amount of 'zombie' clients. Largely, those were false positives, the m_lastAsked variable wasn't updated in all situations. After fixing that variable, I'm seeing around 10% of dead sources (272 out of 2351), which is more realistic. The most common cause for clients to become 'zombie' is that the connection is cut some time during handshaking, and we don't handle all these situations gracefully yet. Due to the large amount of time required to test and analyze these clients (1-2h runtime is minimum required for them to show up in the first place), this is very time-consuming process.
More on the GUI side - I managed to cut 8 pixels from each side of the GUI, winning total of 16px space in width and height. We also tested (for a moment) 24x24px icons on toolbar, but discarded the idea quickly - this interface seems to be heading towards very compact, spartan
interface, where every pixel is carefully considered, and wasting 8px height just to have larger icons doesn't sound like good use for space. It's also expected that the filter-box on top-right will disappear after-all, and become more like firefox's "find-as-you-type" feature, since the practical usefulness of the filtering is near-zero, but it should exist nonetheless.
Sunday, February 19, 2006
Regression testing [zombie clients]
I'v been doing standard regression-testing on ed2k module, which involves analyzing 200-300mb logfiles every few hours. The main thing I was focusing was 'zombie' sources - clients that we asked for download, but then for some reason stopped reasking, thus the client is 'zombie' - never asked again. To aid in that matter, I added 'ed2k deadsource' command to hnsh (only in debug builds) that counts them. So far I'v managed to reduce the number by around 50% with few fixes, but there's still work to be done to catch them all. Seems the ones left currently are disconnections during some part of handshaking.
I also found out more about the memory leak reported earlier. As suspected, this wasn't a Boost library bug, but MSVC C++ runtime library bug; namely, a bug in std::iostream constructor that causes all classes derived from it (basic_stringstream et al) to leak 4 bytes per construction. Boost.DateTime library was patched today (in Boost CVS) to work around this issue; a description about the issue is at MSDN
; Microsoft has fixed the bug, but it won't be available until next release of Visual Studio; until then, there is a workaround available
, but it requires recompiling CRT... It should be noted though that std::ostringstream and std::istringstream (which are heavily used in Hydranode) are apparently not affected by this bug, so it's unclear how large the effect of this bug is on Hydranode engine.
SVN server has been mostly down recently; it seems to crash about once per hour recently, I'v restarted/recovered it at least 10 times today. The bad thing about recovering SVN is that I have to shut down webserver during the recovery as well (since no process may access the SVN DB during recovery). Anyway, since the SVN can't be counted upon to be up, here are source tarballs of current SVN (sorry, no binaries for now).hydranode-r2679-src.tar.gz
Friday, February 17, 2006
The performance optimization made early today morning (see previous post) was a major success; some testers claimed cpu usage drop from 62% down to 28% (P2/200Mhz), and I have been unable to detect any regressions whatsoever inherent from the optimization. Seems you can have the cake and eat it too :)
Gaining confidence from that success, I decided to introduce two more low-level optimizations. The first one is in Scheduler layer, and it tweaks the bandwidth distribution algorithm between sockets slightly, so that the average size of a low-level send()/recv() call is now up to ten times larger than it was before (from 150 bytes to 1500 bytes). This should reduce the TCP overhead considerably.
The second one was done at SocketWatcher, where we call select() every event loop. The trouble with select() is that it returns immediately as soon as ANY of the polled sockets receive an event; however this means with many sockets, we perform the expensive operation of adding all sockets to the list to be passed to select(), and then select() returns almost immediately, saying "socket #10 is readable", and we go over the entire thing again. Now I introduced a 50ms sleep cycle right BEFORE the select() call, thus forcing a delay into the main event loop. This has the effect of having select() return events on multiple sockets during one call, reducing overall CPU usage further.
I also discovered a memory leak in Boost.DateTime library, namely in ptime stream output operator. This caused the current GUI to leak roughly 4kb/s memory; this also causes the core to leak quite large quantities of memory when enabling trace masks (since the times are written to hydranode.log). Currently there's no available fix, since this is deep inside the Boost.DateTime library; however it's effect on release builds is minimal, since those perform very little logging.
Thursday, February 16, 2006
Settings page backend and Library page
Got into proper dev-mode today; first 6 hours resulted in full backend being written for the settings page (gui-side), roughly 350 lines of code. On the protocol and core-side, the backends were already implemented in the past (during the Launcher development). Some minor things still need tweaking there (such as better handling of shared directories listing), but those will be done during second iteration over the GUI.
After lunch and a short break, my focus turned towards library page, so as to finish the first iteration over the GUI. The GUI-side implementation was more or less copy/paste from what we had in transfer page, since these two pages are very similar. Some functionality (custom tabs behaviour) was also refactored into a generic class to avoid some code duplication (those tabs are already being used by three pages now).
Basically, the library page will be exactly like transfer page, except reversed - instead of "Completed" column, there'll be "Uploaded" column; Speed column remains, but will display file's upload speed instead; instead of Status, we show Location. To give you a better idea on what I mean:
With the GUI-side backend (340 lines code) operational, I also implemented the libcgcomm-side implementation of the protocol for shared files listing (also very similar to that of downloadlist). The core-side implementation of the protocol is somewhat more complex, it can be implemented very similarly to that of downloadlist. Still the latter is already 500+ lines of code, so it takes a while to create similar caching mechanism for sharedfiles listing. We also lack some related features on core-side, such as uploadrate calculation for shared files, so that introduces some changes to hncore library and network plugins.
So, with the additional 700 new lines of code today, the GUI is now composed of 2182 lines of C++ code and 2736 lines of XML.
Madcat, ZzZzEdit: Since I couldn't get sleep, I introduced a handcrafted event multiplexing system in low-level sockets to bypass the slow Boost.Signals. Based on profiler data, this should lower overall CPU usage by around 30%. Initial testing didn't reveal any problems, but extended testing is still needed. Revision 2666 contains the changes.
Tuesday, February 14, 2006
With my financial situation still not getting any better, my focus is mainly in that area, which unfortunately leaves little time to deal with hydranode coding. However, I reviewed the feedback so far on the GUI, analyzed the points, and introduced some of the changes to transfer page: (this time using classic skin, since many users still use it):
Also, don't worry too much about the media player integration and such; as expected it got both positive and negative feedback, and it had already been decided from the beginning to have it as an optional add-on feature.
I'm also starting further understand the importance of icons in an user interface - even already with the placeholder icons things are starting to get better. Icons on buttons have multiple effects, one of which is that the buttons often get bigger from that, which improves usability. While the main reason behind icons is to provide means of faster identification of controls (e.g. to avoid reading the text every time), the size increase of toolbar buttons size is also a positive effect.
Sunday, February 12, 2006
Transfer, Library, Statistics and Settings pages
After reviewing and discussing the transfer page with our designer, we reached the conclusion that the filter-bar can completely be dropped from transfer page; the size and type-based dropdown/filters were deemed unneccesery, the network-based filtering is not "hydranode style" (since downloads aren't owned by any specific network), and filtering by type will become obsolete anyway as soon as I get to introducing improved downloadlist, which groups all downloads intro three groups - complete, active and inactive. The filtering functionality will most likely return in slightly different way though - accessible via a keyboard shortcut and/or button, will display a small bar/box near the bottom of the list similary to firefox's "search-as-you-type" feature.
Also, the bottom buttons on tranfer-page were reconsidered, and Clear button was dropped from the listing. Reason is that the other 4 buttons - Pause, Stop, Cancel and Resume, all act similarly - alter the state of selected downloads - while Clear button behaved completely differently, leading the test subjects to confusion. Also, the name Clear looked lot like Cancel, which further introduced confusion; and last, but not least, the name Cancel is used generally in dialogues to dismiss modifications and close the dialog, but here it has a different purpose. Hence, it was renamed to "Remove", which is more straight-forward and avoids confusion.
Library page got a thorough discussion as well; basically, the main purpose for the library is to provide means to manage and use the downloaded media; that means listening to music, playing videos, burning/riping and so on. One point that raised was that this would largely duplicate what Windows Media Player already does, altough it would do it better - support any kind of formats for burning; playing everything without needing separate codecs (most likely using VLC engine) and so on; however, implementing all that will take a lot of time, so while this has been planned since the start, it won't see the light of day anytime soon due to other things having higher priority currently.
However, with that in mind, it turned out that the library page became entirely useless - just as useless as eMule's "shared files" page - there's simply no reason to go there if you can't do anything useful there except view your files. After some brainstorming, we realized that there was actually one subset of features that had been discussed in the past and which actually falls under the same category - namely, release/share manipulation. Basically, "release" is same as "sharing", except "release" is an active
activity, while "sharing" is passive
activity. Making Hydranode releaser-friendly and providing tools to aid both regular users as well as power-users perform releases has been planned since the start, and the library page is the right location in the UI for this functionality.
So the bottom line is that the library page (possibly renamed in the future) will serve two purposes - for downloader, it is a location where to view, sort, manage, play and burn the downloaded data; for those wishing to share content with others, either via passive (ed2k, gnutella) or active (bittorrent, ftp) means, it will provide means to do so in an effective way.
The statistics page got kicked completely from the interface. There's simply no justification for an entire page to contain only statistical data. The need for some statistics data is still present though, and this will be satisfied on frontpage (small graphs and such); extended statistics, if deemed nessecery, will simply become new tabs on the System page. The bottom line is that Statistics isn't an important component of the interface to justify button in the main navigation, but the functionality will still be available via other means, so as to avoid endless complaining of stats-freaks.
As I mentioned yesterday, I did initial layout of Settings page; after reviewing it with our designer, and doing some trivial corrections, it's ready for viewing, so here it is in it's current incarnation:
You also notice I added placeholder icons to the top toolbar; seems we'll be using 16x16px icons there after-all instead of the originally planned 24x24 icons, since 24x24 would simply be too large there and waste precious screen space.
Saturday, February 11, 2006
Full SP2 support, more GUI design topics
On GUI side, I'v been fine-tuning the transfer page somewhat - there were some issues with multi-selection while filters were enabled. Also, I added support for pasting links to the gui (to start downloads). Settings page saw initial layout today, but I haven't managed to review/discuss it with our designer yet, so nothing conclusive there yet. The current idea is to have settings page behave just like any other page - a PAGE, not a dialog. There are somewhat mixed feelings about this - on one hand, it's standard to have settings/preferences as separate dialog; on the other hand, it's bad practice to have a set of buttons (top navigation buttons) all having the same effect (change the content of the bottom side), and then have one button behave differently (open a modal dialog). You can find few entries in GUI Design Hall of Shame
on this very thing, yet many (all?) P2P client interfaces seem to do this.
I also gave thought on the comment in previous blog post, regarding the mentioned usability issue with the filter bar. Yes, I agree that having a search box on the top-right corner is a growing standard; however that means in order to maintain the UI balance, I will also need to put something to the top-left corner (as you'v noticed, the UI is meant to be center-balanced - the bottom buttons are also centered now). Only logical thing to put to the top-left corner that I can think of right now would be a global status indicator, along the lines of "Ok, Online, Core up" etc - roughly same-sized, multi-function display element as the search-box on the right.
As for the filter-bar after we implement the above changes, I don't feel it works at the bottom, since the bottom is reserved for "action toolbar" or "taskbar" - logic being that you move in the UI from top to bottom - switch to correct page, find the object you'r interested in by filtering and/or clicking on list entries, and then perform the operation at the bottom. If you move the filter-bar to the bottom, it moves away from the natural flow in which the user would "parse" the interface.
There are some alternative solutions to the filterbar; for example, some interfaces allow "search-as-you-type" behaviour - when you start typing, a small text-edit box is displayed and filtering applied. This would make the entire filter-bar obsolete - the drop-downs on the filterbar weren't really useful anyway, perhaps only Status was, but the plans are to introduce grouped-view to the entire listing, where downloads are grouped to Complete [finished], Active [Waiting/Downloading] and Inactive [Paused/Stopped]. Canceled downloads should probably be removed from the listing instantly, since there are no operations you can perform on a canceled download (where-as you can "open" a Completed download).
On core-side, I finally
added full support for XP/SP2 limitations workaround - there's a new configuration option, "ConnectingCount" (not the best choice of names, I admit), which basically limits number of concurrent outgoing (half-open) connections, defaulting to 9 on windows and unlimited on other systems. Users running Hydranode on other systems should be warned though that if you have an XP/SP2 box sharing internet, that TCP connection limitation apparently affects ALL systems behind it as well - so even if you'r running Hydranode on linux, but Windows box is sharing net, you still run into this limitation. At least this is what I noticed during my tests - don't take this as absolute truth though, I might be wrong here.
Related to the above, the "half-open" connections suddenly became a very scarce resource, which means I had to fine-tune both ed2k and BT code to lower outgoing connection timeout from 30s to 15s (ed2k) and 5s (bt). Regression tests didn't bring out any issues even when reducing the ed2k timeout to 5s, so it's expected we will drop it to 5s shortly.
I'm also tracking some memory-usage issues that I'v detected recently, with hydranode using 60+mb memory. Towards that end, I added new command in hnsh, 'memstat' (abbr. 'mem'), which displays the amount of memory used by PartData file buffers. In worst-case scenario this can be as high as 0.5*num_downloads (500kb per download), but the average should be much lower.
Thursday, February 09, 2006
Small bits and pieces
The thing with very new code is that there's so much to do at same time, so it doesn't really matter in which end you beat at it, everything needs to be done anyway.
So most of today went to finishing first set of features on transfer page - all the buttons in bottom-bar now function, and the filter-bar mostly works as well - filtering by multiple categories at once doesn't work yet tho.
Usability testing brought out one somewhat important issue - namely the tester was on transfer page, and was intending to perform a search, so he entered the search string into the 'filter text' box instead and clicked 'clear filter' button, before realizing the need to switch to search page first. This is an offset of having multiple pages look very similar. The current proposed solution is to slightly tone the background of each page differently - search as light blue, transfer as green etc, to provide visual hints on where the user is located at. Icons at nav-bar will also help towards that end.
On search-page, we need some kind of progress indicator, and I figured that we'll simply reuse the search input box for the progress indicator (draw it transparently on top of it), and switch the "search" button to "cancel" button while search is in progress. That way the progress of the operation is displayed near/at the location where the operation was started.
Tuesday, February 07, 2006
I figured, what the hell, let's post some screenshots for your viewing pleasure. So without further delay, here's search and transfer pages, in their current incarnation.
Obviously, there aren't any icons (which make a HUGE difference in how a GUI looks/feels like). Furthermore, screenshot can only show just so much; the tabs mechanism on which I worked put most work on today isn't seeable from the screenshots at all.
Basically, in search page if you click on the nonamed, right-most tab, you get a new search tab. This way you can store your previous search and start new one if you want to; or you can reuse the old tab for new search just the same. This is a modification of what most other clients do, however what I disagree with in other implementations is the need to create a new tab for EVERY search. Give user the option of opening a tab, just as their used to doing in web-browsers, instead of creating gazillion of tabs when the user actually has no intention of returning to the previous results.
Also notice the "location" drop-down box on search page; since Hydranode, at least currently, doesn't have a concept such as "download categories", but instead allows setting destination directory for each file separately at API level, I figured maybe this is more flexible at UI level as well. So instead of creating custom categories with different incoming directories in transfer page, you'll just set up your favourite destination locations for files, and can select them from this drop-down box. Also, you can specify any location on-the-fly for the download as well without having to create a category every time you want to download a file to specific location.
On transfer page, the filter-bar on top and the tab-concept work more strongly together. Namely, when you open a new tab, you get an identical page as the previous; however, using the filterbar, you will be able to customize the active page to your liking - perhaps show only files matching certain name, or certain status or type. Filters will be stored across sessions.
Monday, February 06, 2006
Starting GUI development
After a few days of post-release wind-down period and some neccesery dev-systems reinstalls, I'm mostly back in development mood. So far I've managed to generate about 1000 lines of C++ code plus some 2kloc xml generated from qtdesigner. What I have up is main navigation and prelimiary layouts for system/search/transfer pages.
Basically, the UI will be pretty typical to other p2p client interfaces, with main navigational buttons at the top. Currently five pages are planned - System, Search, Transfer, Library and Statistics. In addition there'll be Settings page/window, but the contents of that are not yet fully decided currently.
System page will be the most interesting of the five; in addition to serving as "overview" page for all important information, it will also provide a tab-based (like in IE7 or FF) interface for plugin-specific data, such as server lists, newsgroup contents or IRC chat pages.
There are a number of things about GUI programming that personally I dislike. One major difference from code design / structuring point of view is that you'r using an existing framework
, NOT a class library
. There's a huge difference between those two. In simple terms, in case of a framework
, you need to subclass a lot of framework-provided classes in order to achieve your goals, while in case of a class library
, you get to choose your own class hierarchy, and use the library-provided classes as tools. Many C++ authorities recommend to "prefer composition over inheritance"
, and I strongly agree with that point. This was the reason I chose Boost class library
for Hydranode engine, and the engine itself is also strongly biased towards that idea - plugins rarely need to subclass any of the engine classes.
The fundamental difference between using a framework and using a class library is that if you have a class library, a set of tools, at your disposal, you can set YOUR class hierarchy up the way you like it, the way you understand the problem/solution best, thus creating your OWN framework. However, in case of a framework library
, you are bound with THEIR class hierarchy. Consider that in case of search page, I had to subclass QTabWidget, QTabBar, QWidget (for content frame), QTreeWidget and QTreeWidgetItem. That's just stupid. Granted, I would be able to reduce the subclassing perhaps somewhat, but that was the logical thing to do (and for 3 out of the 5, it was absolutely required).
Another thing that somewhat annoys me is that when developing GUI-like things, one's focus switches from writing cool code towards producing the final product. You suddenly care less about what the underlying code looks like, and focus more on what the product itself looks/feels like. Technically, there's nothing wrong with this concept; however being somewhat a freak about having code look nice, this tendency annoys me. I think it can be accounted to the fact that when you'r writing GUI stuff, you'r lot closer to the end-user than you are when writing low-level, non-gui stuff; also, in case of non-gui stuff, the source code by itself becomes sort of an interface for the product for the developers, so they spend a lot of time making it pretty - since that's how they "use" the product most of the time - by looking at the code. It's no wonder very low-level things, such as Linux Kernel, have very nice and clean codebase - at least visually.
--PS: Screenshots will be available in a few days or so.
Wednesday, February 01, 2006
After the long wait, Hydranode version 0.2.0 is finally here. From the release notes:
Version 0.2 is a major update to Hydranode Engine, focusing towards new features and functionality. Large parts of codebase have been completely rewritten, other parts have been improved significently.
Major new features include support for Bittorrent protocol, more usable shell interface, completely rewritten HTTP support and many performance improvements in eDonkey module.
Special thanks to Hydranode Quality Assurance team: chemical, frop, dani_555, ak, TobiasTheCommie, wubbla
Quick download links: Windows
, Source code
(also needs Boost 1.33.1 headers
), and the full ChangeLog
So, what now? The next thing in the roadmap is user interface, so that's where the focus will be. I did some prelimiary layouting and coding in that area yesterday already, but then realized I need to get 0.2 out of the door before I can concentrate my focus fully on the interface. As with any software piece, the initial versions won't be pretty (the skinning engine is planned as last phase of the user interface development), but I hope to have initial binaries and screenshots available for testing within a week or so.
September 2006 Current Posts