Bibliothek zur Nutzung der MediaWiki-API unter .NET

Für ein kleines Projekt war ich auf der Suche nach einer halbwegs aktuellen Bibliothek zur Nutzung der MediaWiki-API. Wenn man sich auf der entsprechenden Seite in der MediaWiki-Dokumentation umschaut, wird man feststellen das einem nicht all zu viele Bibliotheken zur Verfügung stehen.

Die Auswahl an .NET Bibliotheken fällt eher mager aus

Genutzt habe ich letztendlich die Bibliothek Wiki Client Library, da diese halbwegs aktuell ist und mit meinen MediaWiki-Installationen problemlos zusammenarbeitet. Ein minimales Beispiel zur Bearbeitung einer Wiki-Seite sieht mit der Bibliothek wie folgt aus:

// Init
var client = new WikiClient
{
    ClientUserAgent = "WikiBot"
};

var site = new WikiSite(client, https://wiki.example.com/api.php);

// Login
await site.Initialization;
try
{
    await site.LoginAsync("username", "password");
}
catch (WikiClientException ex)
{
    Console.WriteLine(ex.Message);
}

// Edit site
var page = new WikiPage(site, buildingName);

// Load page
await page.RefreshAsync(PageQueryOptions.FetchContent);

// Update page
page.Content = "new content";
await page.UpdateContentAsync("New page created.", minor: false, bot: true);

// Logout
await site.LogoutAsync();

Über die Nutzung von Generatoren ist es möglich größere Bereiche wie z.B. Kategorien oder Suchergebnisse zu iterieren:

// Iterate all pages
var generator = new AllPagesGenerator(site)
{
    StartTitle = "A",
    NamespaceId = BuiltInNamespaces.Main,
    PaginationSize = 50
};

using (var enumerator = generator.EnumPagesAsync().GetEnumerator())
{
    int index = 0;

    while (await enumerator.MoveNext(CancellationToken.None))
    {
        // Debug output
        var page = enumerator.Current;
        Console.WriteLine("{0}: {1}", index, page);
        index++;

        // Load page
        await page.RefreshAsync(PageQueryOptions.FetchContent);

        // Update page
        page.Content = "new content";
        await page.UpdateContentAsync("Update page.", minor: true, bot: true);
    }
}

Der Quelltext der Wiki Client Library ist auf GitHub zu finden. Lizenziert ist er unter der Apache Licence 2 und damit freie Software.

Rollback-Plugin für WordPress

Neben meinen eigentlichen WordPress-Instanzen betreibe ich einige Entwickler-Instanzen. Dort habe ich ab und an das Problem, das ich bestimmte Plugins in einer älteren Version nutzen möchte. Natürlich kann man nun für jeden Fall die gewünschte Version herunterladen und manuell installieren.

Über WP Rollback können Plugins auf beliebige Versionen zurückgerollt werden

Einfacher geht dies mit dem WordPress-Plugin WP Rollback. Das Plugin ermöglicht es über die administrative Oberfläche von WordPress beliebige Plugins auf beliebige Versionen zurückzusetzen. Dazu muss nur das passende Plugin und die gewünschte Version ausgewählt werden und anschließend wird der Rollback durchgeführt.

Der Quelltext des Plugins ist auf GitHub zu finden. Lizenziert ist das Plugin unter der GPL in Version 2 und damit freie Software.

Clients und Server-Stubs mittels Swagger Codegen erzeugen

Mit Swagger gibt es seit einigen Jahren eine Möglichkeit REST-API sinnvoll zu dokumentieren und zu generieren. Aus einer YAML-Datei, welche die Beschreibung der API enthält kann mit dem Swagger Code Generator (kurz Swagger Codegen) eine entsprechende Client-Bibliothek oder ein Server-Stub erzeugt werden. Eine solche minimale YAML-Datei könnte wie folgt aussehen:

swagger: '2.0'
info:
  description: "API"
  version: "2018.04"
  title: "API"
host: "api.example.com"
basePath: "/v1"
schemes: 
- "https"
paths:
  /tree:
    get:
      produces: 
      - "application/json"
      summary: Returns the document tree
      tags:
      - "Document tree"
      description: Lorem Ipsum dolor sit amet
      responses:
        200:
          description: OK

In dieser Datei wird eine Ressource mit dem Namen tree und für diese eine Get-Methode definiert. Um daraus nun die Client-Bibliotheken bzw. Server-Stubs zu generieren muss der Swagger Codegen über Git bezogen, anschließend kompiliert und paketiert werden:

https://github.com/swagger-api/swagger-codegen.git
cd swagger-codegen
mvn clean package

Zur Erzeugung eines PHP-Server-Stubs mit dem Slim-Framework kann der Swagger Codegen anschließend wie folgt genutzt werden:

java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar generate -i api.yaml   -l slim -o folder/slim

Eine Client-Bibliothek wird auf dem gleichen Weg erzeugt:

java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar generate -i api.yaml   -l javascript -o folder/javascript

In diesem Fall wird eine JavaScript-Client-Bibliothek erzeugt. Die verfügbaren Sprachen bzw. Frameworks für die Clients und Server-Stubs erzeugt werden können, können mit dem Befehl:

java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar langs

angezeigt werden. Die Ausgabe spezifiziert alle vorhandenen Generatoren:

Available languages: [ada, ada-server, akka-scala, android, apache2, apex, aspnetcore, bash, csharp, clojure, cwiki, cpprest, csharp-dotnet2, dart, elixir, elm, eiffel, erlang-client, erlang-server, finch, flash, python-flask, go, go-server, groovy, haskell-http-client, haskell, jmeter, jaxrs-cxf-client, jaxrs-cxf, java, inflector, jaxrs-cxf-cdi, jaxrs-spec, jaxrs, msf4j, java-pkmst, java-play-framework, jaxrs-resteasy-eap, jaxrs-resteasy, javascript, javascript-closure-angular, java-vertx, kotlin, lua, lumen, nancyfx, nodejs-server, objc, perl, php, powershell, pistache-server, python, qt5cpp, r, rails5, restbed, ruby, rust, rust-server, scala, scala-gatling, scala-lagom-server, scalatra, scalaz, php-silex, sinatra, slim, spring, dynamic-html, html2, html, swagger, swagger-yaml, swift4, swift3, swift, php-symfony, tizen, typescript-aurelia, typescript-angular, typescript-inversify, typescript-angularjs, typescript-fetch, typescript-jquery, typescript-node, undertow, ze-ph, kotlin-server]

Lizenziert ist der Swagger Codegen unter der Apache Licence in der Version 2 und somit freie Software.

Garbage Collection Log erstellen und auswerten

In regelmäßigen Abstand führen Java-Applikationen eine sogenannte Garbage Collection durch. Dabei werden Objekte welche nicht mehr benötigt werden entfernt und somit der Speicher der Anwendung bereinigt. Die Ausführung der Garbage Collection kann während der Ausführung der Applikation mitgeloggt werden:

java -Xloggc:garbage.log -jar application.jar

Der Parameter -Xloggc spezifiziert die Datei in welche das Log geschrieben wird. Mit Hilfe dieses Logs können Probleme der Applikationen analysiert werden. Ein Beispiel für ein solches Log könnte z.B. so aussehen:

Java HotSpot(TM) 64-Bit Server VM (25.144-b01) for bsd-amd64 JRE (1.8.0_144-b01), built on Jul 21 2017 22:07:42 by "java_re" with gcc 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
Memory: 4k page, physical 8388608k(122952k free)

/proc/meminfo:

CommandLine flags: -XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC 
4,347: [GC (Allocation Failure)  33280K->8385K(125952K), 0,0125825 secs]
4,475: [GC (Metadata GC Threshold)  12196K->8961K(125952K), 0,0061766 secs]
4,481: [Full GC (Metadata GC Threshold)  8961K->6026K(87552K), 0,0206784 secs]
16,232: [GC (Allocation Failure)  39306K->15981K(87552K), 0,0095999 secs]

Zur Auswertung kann, neben vielen anderen Tools, der Webdienst GCeasy, welcher sich selbst als Universal GC Log Analyzer bezeichnet, genutzt werden.

Die Analyse des Garbage Collection Logs

Mit Hilfe der Auswertung können eventuelle Probleme im Zusammenhang mit der Garbage Collection besser eingegrenzt und analysiert werden. Zu finden ist der Dienst unter gceasy.io.

RPG Maker MV Autorun-Event nur einmal ablaufen lassen

Beim RPG Maker MV gibt es Events. Mit diesen Events kann das Spiel gestaltet werden. Für ein Intro-Event stand ich nun vor dem Problem, dass das Event nur einmal ausgeführt werden sollte. Bei mir wiederholte sich das Event allerdings ständig. Da es sich um ein Autorun-Event handelte, startete dieses beim Betreten des Raumes jedes Mal von Neuem. Die Möglichkeit das Event über den entsprechenden Event-Befehl zu löschen funktionierte in diesem Fall ebenfalls nicht. Das Löschen eines Events kann nur dann genutzt werden, wenn der Spieler nicht während des Events auf eine andere Karte transferiert wird.

Seite 1 des Events

Die Lösung für dieses Problem ist relativ einfach. Auf der ersten Seite des Events erstellt man das eigentliche Event. Als Auslöser wird hierfür Autorun gewählt. Am Ende des Events wird der Selbstschalter A auf EIN gesetzt. Anschließend wird eine zweite Seite erstellt. Auf dieser Seite kann der Auslöser ebenfalls auf Autorun gestellt werden; es ist allerdings nicht zwingend nötig. Wichtig ist hingegen, dass die Bedingung Selbstschalter ausgewählt wird und mit dem Selbstschalter A verknüpft wird.

Seite 2 des Events

Bei der Ausführung des Events führt dies nun dazu, dass sobald der Selbstschalter A gesetzt ist, statt der ersten Seite des Events, die zweite Seite ausgeführt wird. Da diese keine Befehle enthält ist das Event damit beendet. Theoretisch kann man so in einem Event eine ganze Kaskade von fortschreitenden Eventteilen schaffen. Der Hintergrund hier ist das die Eventseiten dafür gedacht sind ein Event unter unterschiedlichen Bedingungen anders zu gestalten. Die Dokumentation des RPG Maker MV erklärt das Ganze so:

[Event Pages] are responsible for this. Event pages [conditionally] determine the contents of events. You can have one event with up to 20 event pages, and specify different images, triggers, and what processes are run for each. In other words, you can [conditionally] choose from 20 different events for one map event.