Martin Lantzsch
Software Entwickler
29. März 2013

Django JSON POST decorator

29. März 2013 - Geschrieben von Martin - Keine Kommentare

Für den Django API Server bei Resigame habe ich einen neuen Decorator geschrieben, welcher Daten im JSON Format, die per POST übermittelt werden automatisch in eine Liste konvertiert und nach „request.POST“ schreibt. Brauchen wir, da die Daten via Backbone.js im JSON Format an die REST API gesendet werden.

resigame-api/decorators.py

from StringIO import StringIO
import json
 
 
def post_json(function):
    def wrap(request, *args, **kwargs):
        if request.raw_post_data is not '':
            try:
                request.POST = json.load(StringIO(request.raw_post_data))
            except:
                print 'invalid json in request.raw_post_data'
        return function(request, *args, **kwargs)
 
    return wrap

Einfach den Decorator @post_json anhängen, wenn z.B. folgende Daten gesendet werden:

{"x":100,"y":100,"name":"Resiiiiiiii"}

Anschließend befindet sich eine Liste mit den Daten in request.POST. Als wenn die Parameter und Werte normal übergeben worden wären.

24. März 2013

Dynamisches JavaScript in den Chrome Developer Tools

24. März 2013 - Geschrieben von Martin - Keine Kommentare

Das neue Resigame ist ja komplett Single Page, sprich alle Inhalte werden nachgeladen und dynamisch aufgebaut ohne dass die Seite auch nur ein einziges mal neu geladen werden muss.

Hierbei lade ich natürlich die JavaScript Dateien nur dann wenn ich sie brauche, also über eine Requirejs ähnliche Schnittstelle in meine App. Ich habe das ganze noch ein wenig „verfeinert“, bzw. an meine Bedürfnisse angepasst.

Das Problem an der Sache ist nur, dass diese Dateien dann natürlich in den Chrome Entwickler Tools unter „Source“ nicht auftauchen, weil dieser Tab nur die im HTML – beim Seitenaufbau – existenten Scripts erkennt. Um das zu umgehen hängt man einfach in die js Dateien ganz unten folgenden Kommentar:

//@ sourceURL=/static/lib/resigame/map.js

natürlich muss der Pfad angepasst werden. Übrigens ist dieses Verhalten ganz praktisch, wenn man auch in der Entwicklung schon mit kompilierten/komprimierten JavaScript Dateien arbeiten möchte, denn hängt man den Source Url Kommentar unten an jenes komprimiertes File an, wird das dort angegebene als sog. Source Map verwendet sprich, in den Entwickler Tools sieht man dieses und man kann bequem Breakpoints im Klartext Quellcode setzen. Allerdings muss hierzu ein Kompiler verwendet werden, der Source Maps unterstützt, dass ist meines Wissens nach momentan nur der Closure Compiler von Google. Mehr Informationen zu den Source Maps hier: http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/

10. Februar 2013

visualstudio.com Computer Name geändert

10. Februar 2013 - Geschrieben von Martin - Keine Kommentare

Mit folgendem Kommando kann man das Repository wieder gangbar machen, wenn der Computername geändert wurde:

C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE>tf workspaces /updateComputerName:ALTERCOMPUTER /s:https://DEINWORKSPACE.visualstudio.com:443/DefaultCollection
Auflistung: https://DEINWORKSPACE.visualstudio.com/DefaultCollection
Arbeitsbereich  Besitzer        Computer Kommentar
--------------- --------------- -------- --------------------------------------
ALTERCOMPUTER   Martin Lantzsch NEUERCOMPUTER

23. Januar 2013

Die DLL „SQLite.Interop.dll“: Das angegebene Modul wurde nicht gefunden.

23. Januar 2013 - Geschrieben von Martin - Keine Kommentare

Ich habe eine C# Projekt Mappe mit einer WPF Anwendung und einer Konsolen Anwendung. Die WPF Anwendung besitzt alle Klassen, DLLs, etc. Der Konsolen Anwendung habe ich anschließend abhängig von der WPF Anwendung gemacht und die Build Reihenfolge so gestellt, dass die Konsolenanwendung bei erstellen der Projekt Mappe als zweites kompiliert wird.

Beim Debuggen trat dann immer folgender Fehler auf. Allerdings nur beim Debuggen, beim Ausführen der .exe aus dem /bin/Debug Ordner des Projektes gab es keine Probleme.
Die DLL "SQLite.Interop.dll": Das angegebene Modul wurde nicht gefunden.

Ich dachte erst an nicht aufgelöste Abhängigkeiten, also habe ich mir mit dem „Dependency Walker“ die DLL genauer angesehen:
Dependency Walker
Error: Modules with different CPU types were found.
CPU Type, das Problem kommt mir bekannt vor. Also habe ich mein Konsolen Projekt in den Projekteinstellungen von „Zielplattform“ – „Any CPU“ auf „x86“ gestellt und hey, nun startet es. Warum weiß ich leider nicht, ich kann es mir nur so erklären, das er beim kompilieren „Any CPU“ nicht auf die in x86 und x64 DLLs in dem GUI Projekt mappt. Denn das GUI Projekt startet mit „Any CPU“, den selben DLLs und der selben Klasse, die auf die DLLs zugreift.

10. Januar 2013

ResiOS lebt

10. Januar 2013 - Geschrieben von Martin - 2 Kommentare

ResiOS lebt
Eigenen x86 Kernel mit C und Assembler schreiben. Check.

6. Januar 2013

NodeJS MySQL pool

6. Januar 2013 - Geschrieben von Martin - 2 Kommentare

Momentan arbeite ich daran Resigame 2.0 auf NodeJS Basis zu entwickeln. Da abzusehen ist, dass auf Resigame wieder sehr hoher Traffic entstehen wird, wird das ganze Performance optimiert entwickelt. Cluster, SQL Pooling, etc.

Gestern habe ich mir ein Modul für den MySQL Pool geschrieben, denn bei vielen NodeJS Applikationen wird entweder für jeden HTTP Request eine MySQL Verbindung verwendet oder eine für alle.

Das Problem bei einer Verbindung pro HTTP Request ist, dass die Verbindungen bei hohen Nutzerzahlen sehr schnell ausgehen (MySQL max connections) und man ggf. ein paar Sekunden auf die nächste freie Verbindung warten muss.

Bei der Methode mit einer Verbindung, die für alle Nutzer verwendet wird, ist natürlich die Performance sehr bescheiden. Aufwändige Querys können die ganze Applikation stark ausbremsen.

Also habe ich einen MySQL Pool entwickelt, dieser wird beim starten der Anwendung erzeugt. Man übergibt die „poolsize“ – also die Anzahl der Verbindungen die hergestellt werden sollen (diese muss natürlich unter der maximalen Anzahl an Verbindungen, die der MySQL Server zulässt liegen) und die Zugangsdaten zum Datenbankserver. z.B.

var pool = new require('/helpers/pool')({
	poolsize: 50,
	mysql: {
		host: 'localhost',
		user: 'root',
		password: 'root',
		database: 'resigame'
	}
});

Querys können nun direkt an den Pool gesendet werden:

pool.query('SELECT * FROM users WHERE userID = ?', [userID], function(err, results) {
	// whatever
});

Der Aufruf fügt den Query zur Warteschlange hinzu und sieht nach ob gerade eine Verbindung frei ist. Wenn ja wird diese gleich verwendet, ansonsten dauert es bis wieder eine Verbindung frei wird. (Ergo, je mehr Benutzer die gleichzeitig auf die Datenbank zugreifen, desto höher die poolsize –> mehr Performance).

Hier der Quellcode, ich werde ihn die Tage noch ein wenig erweitern und dann auf GitHub stellen.

/** 
 * MySQL pool to hold multiple connections to the database server
 *
 * @author	Martin Lantzsch <martin@linux-doku.de>
 */
 
var mysql = require('mysql');
module.exports = function(config) {
	this.freeConnections = [];
	this.queryQueue = [];
 
	this.createConnection = function(details) {
		var connection = mysql.createConnection(details);
		connection.connect();
		connection.number = this.freeConnections.length;
		this.freeConnections.push(connection);
	};
 
	this.query = function(command, params, callback) {
		if(typeof(params) == 'function') {
			callback = params;
			params = [];
		}
 
		this.queryQueue.push({
			command: command,
			params: params,
			callback: callback
		});
		this.work();
	};
 
	this.work = function() {
		var self = this;
		if(self.queryQueue.length > 0) {
			if(self.freeConnections.length > 0) {
				var query = self.queryQueue.shift();
				var connection = self.freeConnections.shift();
				connection.query(query.command, query.params, function(err, results) {
					if(err) throw err;
					query.callback(err, results);
					self.freeConnections.push(connection);
					if(self.queryQueue.length > 0)
						self.work();
				});
			}
		}
	};
 
	for(i = 0; i < config.poolsize; i++) {
		this.createConnection(config.mysql);
	}
 
	return this;
}

20. November 2012

jQuery click nicht auf Childs anwenden

20. November 2012 - Geschrieben von Martin - Ein Kommentar

Wenn man mit jQuery einen Klick Event Handler auf ein Element setzt, so wird dieser auch automatisch bei klick auf ein Kindelement ausgeführt.

Um das zu umgehen, habe ich mir folgende if Abfrage mit eingebaut, die prüft ob das geklickte Element auch wirklich das Element ist, dass im Event Handler angegeben wurde und keines der Kind Elemente.

$('.element').click(function(data, handler) {
	if(data.target == this) {
		// Code
	}
});

29. Oktober 2012

Bitfelder/Bitfields mit PHP

29. Oktober 2012 - Geschrieben von Martin - Keine Kommentare

Heute beschäftigte ich mich damit Bitfelder in PHP abzubilden. In meinem Fall wurde eine Variable mit verschiedenen Flags befüllt. Am altbekannten
OOP Beispiel Auto könnten diese Flags zum Beispiel Ausstattungsmerkmale sein:

  • Panoramadach? Ja/Nein
  • Navigationssystem? Ja/Nein
  • Alufelgen? Ja/Nein

Um diese Werte nun besondern Speicherplatzschonend zu sparen, wollen wir nun alles in ein Bitfeld speichern. Ein Bitfield mit Flags ist eigentlich nur eine Folge von Nullen, auf der Bits gesetzt (0 –> 1) werden können.

Beispielsweise hat unser Auto die Merkmale Panoramadach und Alufelgen, dann sieht dieses Bitfield so aus:

101

Gelesen wird die Ausstattungsmerkmalliste von oben nach unten und das Bitfeld von rechts nach links. Die erste 1 sagt, ja wir haben ein Panoramadach, die 0 sagt Nein wir haben kein Navigationssystem und die zweite 1 ganz links verrät Ja wir haben Alufelgen.

Mit PHP können wir dieses Bitfield so erzeugen:

$bitfield;
$bitfield |= 1 << 0; // An die erste (also 0te) Stelle im Bitfield eine 1 setzen
$bitfield |= 0 << 1; // An die zweite eine 0
$bitfield |= 1 << 2; // Und an die dritte eine 1

In der zweiten Codezeile gibt die 1 an, dass das Bit gesetzt ist, das „<<" setzt dann diesen Vorrausgehenden Wert auf die nachfolgende Stelle (in dem Fall 0) im Bitfeld.

0 << 0 // erstes Bit ist Null
0 << 1 // zweites Bit ist Null
0 << 2 // drittes Bit ist Null
1 << 3 // viertes Bit ist Eins
1 << 4 // fünftes Bit ist Eins

Nun können wir uns mit folgender Funktion die Binärzahl ausgeben lassen:

echo base_convert($bitfields, 10, 2);

Dieser Funktionsaufruf konvertiert die Zahl von der Basis 10 zur Basis 2 und gibt sie aus:

101

Passt. Nun können wir noch prüfen, ob z.B. das erste Bit gesetzt ist:

if($bitfield & 1 << 0)
    echo 'Das erste Bit ist gesetzt.';

Hier wird geprüft, ob das gesetzte Bit in der Bitfield Variable und „1 << 0" gleich sind. Wenn ja ergibt der Ausdruck true. Damit das ganze halbwegs dynamisch bleibt und man nicht immer die Bitzuweisung von Hand tippen muss, so können wir diese auch in einer Varibale oder Konstante speichern:

define('MERKMAL_PANORAMADACH', 1 << 0);
define('MERKMAL_NAVIGATIONSSYSTEM', 0 << 1);
define('MERKMAL_ALUFELGEN', 1 << 2);
 
$bitfield;
$bitfield |= MERKMAL_PANORAMADACH;
$bitfield |= MERKMAL_NAVIGATIONSSYSTEM;
$bitfield |= MERKMAL_ALUFELGEN;
 
if($bitfield & MERKMAL_ALUFELGEN)
    echo 'Jep, das Auto hat Alufelgen.';