wiredfool

Archive for the 'Programming' Category

Slicehost

Round about mid-November, email sorta blew up here. It took a good weekend of not so spare spare time to get it sorta back working, including some horrific hacks that really shouldn’t be necessary and turned out to have subtle bugs that would do things like drop paypal emails on the floor. And it all started because spamhaus put the entirety of slicehost into a policy block list. Slicehost is a virtual machine provider where people tend to start up a machine and leave it running, doing long term businessy or useful stuff until the need arises for something bigger. That’s ok, except that mail comes into my slice, then gets forwarded to a place that uses that policy black list. PITA really.

And after all the effort to go through and fix that, now I needed to update that slice from oldstable to current debian stable because clamav (the virus scanner) basically blew up on an update and wouldn’t run in daemon mode. So, it forks a process for each incoming mail, which kills the performance and makes Slicehost send me nasty emails about swapping and heavy disk access. So, I need two things: currentish code and updates and more memory. And the best way to add memory is to use less of it. And the image size of the programs that I’m using is a lot smaller (1/2-1/3) in the 32 bit distribution vs the 64 bit distribution. This is something that other people have noted with Slicehost vs other virtual private server providers.

So, Upgrading Etch (x64) to Lenny (i386). Or shall I say, how to install 32 bit Lenny on a 64 bit slice. The adventurous could likely do this on one slice, I’m building a new one so that I don’t kill services while I twiddle with things. There’s a really useful wiki article that covers the majority of what needs to happen. The only real changes are to use arch=i386 in the debootstrap command, and make sure that lenny is the distribution that you select anywhere there’s an etch in that article. Also, you need to delete the existing lib64 directory when you blow away the initial install.

After that, the important bits of making athe mail server play nice include merging all the old configs, which basically works. The Clamav user needs to be added to the amavisd group and clamav-daemon restarted. I also had to set rw permissions on /dev/null for everyone, I’m not sure if that’s a bug in the udev bits or in the copying of the devs over to the new system.

If I need more memory, I may move the one website off that machine and onto Dreamhost, as I see that they have started doing WSGI now, and that would make it reasonably easy to host this pylons site.

(edit: and then, just to make sure that I was paying attention, Dreamhost decided to deliver additional copies of all email in my pop account every time I checked starting 24 hours after I did this.)

No comments

Random Linkage

An Open Tab Link Dump:

No comments

Fun with SWIG, wxPython, and the Windows event system

One of the things that I do at the day job is write support for various models of check scanners into our scanning application. It’s a python app, running on Windows using wxPython for the interface. And the one constant in the whole thing is that no two scanners work alike, connect similarly, or have remotely similar APIs. So far, I’ve done:

  • Serial
  • Serial protocol over Ethernet
  • XML over HTTP
  • COM Based
  • COM Based with Event Callbacks
  • SWIGified dll interface
  • SWIGified dll interface, with Event Messages

The last scanner that I worked on (which shall go unnamed due to NDA (and really, it’s a published API. Why an NDA? (It’s not like people developing for your scanner wouldn’t like it if everyone copied the same interface))) was the most involved so far, at least to the point of getting the first image out of it. After that, it actually was pretty simple. (And to be fair, there is something called the Ranger API, which does support a good number of scanners, but not all of the ones that we’re interested in. It’s up there, under COM with event callbacks).

Step 1: Getting a SWIG wrapper of the dll to compile using Visual Studio .NET 2003. I’m using VS.net 2003 since I have to stay with what compiled Python 2.4. So, it’s not modern, but it works for what I need it to do. There are a lot of little bits to getting a working SWIG wrapper, especially with debug mode. I gave up on a full debug version of this one due to the difficulty of building a debug version of wxWindows/wxPython on top of all the other python modules that I’d need. First thing is to download SWIG and any other dependencies. I’m on the 1.3 tree of SWIG, later versions may differ. You need to start with a dll project, add the appropriate headers and whatnot. The python libraries and the driver libraries need to be available for linking, the output needs to be put in a _{module}.pyd file (or _{module}_d.pyd for the debug version). There needs to be a SWIG .i interface file with a custom build step of:

swig.exe -python -o "$(ProjectDir)\$(InputName)_wrap.cxx" "$(InputPath)" 

with an output of “$(ProjectDir)\$(InputName)_wrap.cxx”

A minimal .i file for wrapping a windows dll:

%module XVX
%{
/* Includes the header in the wrapper code */
#include "stdafx.h"
#include "XXinterface.h"
%}

/* Parse the header file to generate wrappers */
%include <windows.i>
%include "XXinterface.h"

This .i should swigify and compile, but is not the most useful thing in the world. I had trouble linking, even though all the files to be linked were available. I finally tracked it down to the calling convention — where the last SWIG dll wrapper I made used fastcall, this one required cdecl.

Step 2: Getting a usable hWnd reference from wxPython to a SWIG wrapper so that it worked. The window handle as returned from wxPython’s window.GetHandle() is a python int, which SWIG doesn’t like to automatically convert to a hWnd. So, there’s a little typemap magic in the swig interface file to take that Python integer and turn it into something usable.

/* handle hwnds */
%typemap(in) (HWND Handle) {
    $1 = (HWND) ((int)PyInt_AsLong($input));
}

It’s a little ganky in that I’m taking a random integer and making it a window handle, but looking at all the typedefs, I’m pretty sure that it’s a valid approach. What I’m not 100% sure of is if this will work on 64bit machines. I reserve the right to revisit this when I have a 64bit test machine with dev tools.

Step 3: Hooking the Event system so that we could catch ON_MESSAGE events. The sample code I have is for a MFC C++ app, and it has a message map:

BEGIN_MESSAGE_MAP()
  ON_MESSAGE(CUSTOM_EVENT,myHandler),
  ...
END_MESSAGE_MAP()

It turns out that while wxWindows/wxPython does get most events (mouse, command, menu, etc) and allow them to be handled by registering a handler, the ON_MESSAGE event is not one of them. The messages come into the application through a WndProc. The only reference I found in google for this was a faq page which references a MSWWindowProc that you have to override. That didn’t appear to work, which led to this list message (which is archived at a few places on the web, but on devshed.com, it doesn’t have the all important link to the answer) that links to code for overriding the WndProc and getting all the messages that you need. Once you have that, it’s a simple matter of filtering for the message type sent by the driver.

Step 4: Fleshing out the SWIG interface so that it’s not quite as painful to use. There are a lot of methods that pass back short strings in a buffer that you provide. That’s easily handled using a typemap pair in the .i file. This fragment will take the char* outString, BYTE MaxLen pair, wherever they appear, and drop them from the required python arguments of the function, and append them to the result. It could be a bit better, in that it returns all 255 characters from the buffer and it returns an array of [boolean, string] to python. I’m still working on a fix for that.

/* handle the strings */
%typemap(in,numinputs=0) (char* outString, BYTE MaxLen)(char s[255]) {
    $1 = s;
    $2 = 255;
}
%typemap(argout) (char* outString, BYTE MaxLen){
    $result = SWIG_Python_AppendOutput($result, SWIG_FromCharPtrAndSize($1,$2));    
}

I tend to target named parameters, rather than target any type combination like char*, BYTE. It’s easy enough to apply this to other names:

%apply (char* outString, BYTE MaxLen) { (char* ErrorString, BYTE MaxLen) }; 

Next, the ON_MESSAGE event has two parameters, a message and one that’s either a pointer or an int. Since that pointer is delivered directly to python without being able to typemap it to something else, I’ve added a couple of convenience methods for getting the contents of that pointer. (without pulling ctypes into it) The typemap does something similar to the hWnd typemap above, and the inline function just returns my input, but SWIG will take that pointer and turn it into the python representation of that structure.

%typemap(in) (ImagesStruct *pImageStruct) {
    $1 = (ImagesStruct *) PyInt_AsLong($input);
}

%inline %{
ImagesStruct * WINAPI _GetImageStruct(ImagesStruct *pImageStruct ) {
    return pImageStruct;
}
%}
No comments

Updating Ubuntu, Part 2

I’ve also just updated another one of my ubuntu machines, the netbook, to the latest 9.04 netbook remix that was released yesterday. It had been running an 8.10 eeebuntu release that had some issues. It’s main issue was that it didn’t like waking up from suspend with the GIU intact. Normally, it required killing X and restarting it, which is about as disruptive to working as rebooting the whole machine.

This time, I didn’t bother with an update, it was a clean install on a different SD card. That makes it easy to go back to the previous install by rebooting ad switching the cards. Though, it meant I had to spend another $12 for an 8 gig card.

It appears that all the hardware of my 901 is recognized: the wifi, ethernet, camera, bluetooth, and the USB760 3g dongle. (though, I still have to do a little patch to prevent the dongle from showing up as a drive first). And, most importantly, the suspend and resume sleeping works again.

I could still go into the many ways that this netbook is not an apple product, and I still probably will. But, it does web, email, and ssh, with the occasional reboots into windows to deal with windows specific work stuff.

No comments

Updating Ubuntu

On of my main linux machines was running Ubuntu 6.06LTS, which is a long term support release from the middle of 2006. It was getting a little long in the tooth (firefox 1.5 anyone?) and that was getting tiresome.

So yesterday, I bit the bullet and did the upgrade to the newest long term support release, from last spring. Following the directions worked well enough, except for a couple of packages in the openoffice 2.4 release that I had installed. There were a set of them with circular dependencies, so they couldn’t be removed, which in turn were blocking a newer bugfix of openoffice 2.4, in turn, that was blocking the package manager from doing anything useful like updating emacs from version 21 to 22.

Apt is a good package manager, but sometimes it gets into states that aren’t easily resolved. If you get conflicting messages about something being installed, that’s a good sign that you’re there.

The normal solutions didn’t work :

sudo apt-get -f install 
sudo apt-get -f remove
sudo apt-get dist-upgrade

Were all hopeless.

What finally worked was downloading two upgraded packages directly (libhsqldb-java adn openoffice.org-base) and installing them manually via dpkg, and then clearing out all the circular references with:

sudo dpkg -r openoffice.org-kde-integration
sudo dpkg -r --force-all openoffice.org-core01
sudo dpkg -r --force-all openoffice.org-core02 
...

Dpkg can force things that apt-get can’t, or won’t do. After that, sudo apt-get upgrade -f dist-upgrade was enough to make everything work properly.

Finally, there’s a package archive for the shiny new openoffice 3 packages, but it takes some digging to find the archive key and the keyserver.

##repo for open office3
deb http://ppa.launchpad.net/openoffice-pkgs/ubuntu hardy main
deb-src http://ppa.launchpad.net/openoffice-pkgs/ubuntu hardy main

gpg --keyserver keyserver.ubuntu.com --recv-keys 60D11217247D1CFF
gpg -a --export 60D11217247D1CFF | sudo apt-key add -
No comments

Things I’ve noticed about the new iMac

It’s running leopard, and it’s new, fast and all that. Which is all different from what I’ve had before.

  • It’s fast. It’s amazing what going from 2.5 yr old laptop tech to current desktop tech will do, even if I didn’t get a quad core in it. And 2×24″ monitors is nice for programming.

  • The screen is not as good as my Dell 2407WFPHC, even when calibrated. There’s a distinct shift to the color cast of the backlight from side to side, and the backlight intensity varies as well. It may be a subtle angle thing, I’m not sure I can tell. I’m also not getting it to be anywhere near as warm as the calibrated Dell, even when I’m using the same target profile for both monitors.

  • Waking the external display from sleep goes to static. It’s the first time I’ve seen a machine snowcrash.Even if it does just mean that I have to powercycle the display.

  • Fast user switching and terminal and multiple monitors don’t play well together. All the terminal windows end up on the main display when switching back. Maybe I should just use xterms, since they don’t have the same problem.

  • iTunes stops playing when I swap users using fast user switching. PITA when I just want to check my mail. Also, I can’t keep a phone call on gizmo through switching users. What I’d really like to do is dedicate one ’space’ to each user, and just switch without login issues and such. Not sure that’s possible though.

  • I can’t control the headphones and the speakers separately. I’d love to do something complicated to the sound routing like: Alerts-> speakers. Incoming Phone call rings -> both. Music -> switchable. But most importantly, incoming phone rings always to the speakers, no matter what, so that I can hear it if I’m not at my desk. And it’s not like it’s exactly easy to find the headphone jack, since it’s behind the computer.

No comments

Moderation

I’m a moderator on a really big flickr group, and we’ve been running out of human power to do the moderation. There’s just too much traffic. So, My mind goes to automation and whatnot, and I’m winding up building something to help.

It’s essentially a webapp, in python.

I’m reminded that while the names have changed, we’re really no better off than we were 4 years ago in the python webapp space. There are tons of frameworks, incorporating any number of competing templating engines, object-relational mappers, and other middleware. It’s just that they’re now a bit more rails influenced. I’d use my own templating and ORM, but it’s all work related now, and I don’t want that dependency now. This will wind up being open-sourced at some point soon. And it’s a good learning experience to work on one of the more modern packages for a while, even if it does make things harder in the short run.

And they still don’t deploy easily on commodity hosting. You’d think that the Rails Revolution would helped that part, as it’s pushed fcgi and proxying to places where id hasn’t gone before.

But really, if I write PHP, it just works on any webhost. You’d be hard pressed to find a webhost these days that can’t do a minimal php/mysql website. I farted with python for two evenings on Dreamhost, and kept running into strange problems that might be the framework, might be the web adapter, and might just be the shared environment. (fcgi must be group writable? really?) So far, I’m 5 evenings into it total. So 2 evenings is a pretty good setback in the scope of this project.

More to come on this project later.

No comments

Remote Growl Notifications

For reasons that may be obvious, sometimes I want my servers to tell me something, and get my attention in a manner a bit more direct than via email or rss. (If I’m busy, I’m not checking my email. If I’m checking my rss, I’m not busy) And for reasons of geography, sms messages don’t work. Well, cells don’t work, so I don’t actually carry my cell, so. Well, It’s just not effective.

So, I need a couple levels of notification above trawling email or logs. One to interrupt me with bad but not fatal problems, and one to get my attention if I need to know now.

The lower level, interrupt me, for bugs that really shouldn’t exist, problems with important customers, or things that I need to be bothered about until I fix them. The more severe stuff is akin to the raid array losing a drive or deciding to take an impromptu vacation.

So. The best thing I’ve found for notification for things that I want to know is Growl. It pops up a little notification on screen, politely, and it can receive messages over the net. Unfortunately, it’s UDP, and there are a couple of NAT boxes between me and the servers. If it was TCP, it would be a simple matter of remote port forwarding with ssh. I always have a connection open, so it’s just a matter of adding yet another port through there. But it’s UDP, and ssh doesn’t forward UDP.

There are solutions out there using netcat (here and here and so on) all of which tie in a few netcat processes into the tunnel to listen on UDP, send TCP through the tunnel, Listen on TCP on the other end, and forward UDP to the end destination.

That should work, but what I was finding was that the netcat listener on the far end would listen for exactly one UDP connection, and then stop. Once the initial socket closed, nothing further would get through. A few hours of mucking around with this while dealing with other interrupting issues and I had enough. 10 minutes later, I had a pair of python servers that would do the UDP and TCP listening. So far they’ve been far more reliable than the netcat solution.

This runs on the far end:

#!/usr/bin/env python
import SocketServer
from socket import AF_INET, SOCK_DGRAM, SOCK_STREAM, socket
import sys

GROWL_PORT=9887
TCP_PORT=19887
DEST='192.168.10.98'

class growl_udp_handler(SocketServer.DatagramRequestHandler):
    def handle(self):
        addr = ("localhost", TCP_PORT)
        s = socket(AF_INET,SOCK_STREAM)
        s.connect(addr)
        s.sendall(self.rfile.read())
        s.close()

u = SocketServer.ThreadingUDPServer(('0.0.0.0',GROWL_PORT), growl_udp_handler)
u.serve_forever()

and this on the local side.

class growl_tcp_handler(SocketServer.StreamRequestHandler):
    def handle(self):
        addr = (DEST, GROWL_PORT)
        s = socket(AF_INET,SOCK_DGRAM)
        s.sendto(self.rfile.read(),addr)
        s.close()

t = SocketServer.ThreadingTCPServer(('0.0.0.0',TCP_PORT), growl_tcp_handler)
t.serve_forever()

I’m hoping that this is reliable enough that I spend more time debugging the subject of the notifications rather than the notifications themselves.

No comments

Writing AppleScripts That Dynamically Target Either Safari or WebKit

This has been a missing part of my photo workflow for a while:

Daring Fireball: Writing AppleScripts That Dynamically Target Either Safari or WebKit.

My workflow involves opening a page of pics in safari, looking at bigger ones, then dumping the whole lot into lightroom. And that only works in Safari, because I haven’t gotten around to making Webkit work.

No comments

Emacs strikes back

While trying to setup a key for the last keyboard macro in emacs (from Steve Yegge’s emacs page), somehow I got my f key bound to a game of 5×5 rather than binding my f5 key to the macro.

Makes things difficult. Rather than doing the easy thing by quitting and restarting, I made myself fix it. There’s a useful function called M-x describe-key which will give you the binding for a key. From that, I found that letters were bound to self-insert-command, and that the f was indeed bound to something else entirely.

So evaling this: (global-set-key "f" 'self-insert-command) gave me back my f key. Of course, I had to copy and paste in the effs in that command.

No comments

Next Page »