Skip to content

Aufbau eines Moduls

Jedes Modul erfüllt goroku.Module. Das Einbetten von goroku.Base liefert einen Standardwert für alles außer Name und Commands — nur diese beiden Methoden musst du schreiben.

go
type Module interface {
	Name() string
	Strings() map[string]string
	Init(client *CustomTelegramClient, db *Database) error
	ClientReady() error
	OnUnload() error
	OnDlmod() error
	Commands() map[string]CommandHandler
	Watchers() []WatcherHandler
}

Pflicht

Name

Die Identität des Moduls in .help, .unloadmod und der Konfigurationsoberfläche. Es ist zugleich der Go-Typname und der Schlüssel, unter dem deine Daten liegen.

go
func (m *Weather) Name() string { return "Weather" }

Commands

Ordnet einem Befehlswort einen Handler zu. Nutzer tippen das Wort nach dem Präfix, aus "weather" wird also .weather.

go
func (m *Weather) Commands() map[string]goroku.CommandHandler {
	return map[string]goroku.CommandHandler{
		"weather":  m.WeatherCmd,
		"forecast": m.ForecastCmd,
	}
}

Ein CommandHandler ist func(msg *goroku.Message) error. Ein zurückgegebener Fehler wird dem Nutzer gemeldet; der Dispatcher fängt zudem Panics ab, ein Absturz in deinem Handler legt den Bot also nicht lahm.

Optional, mit Standardwerten aus Base

Strings

Text für Nutzer und Quelle für m.T. Zwei Schlüsselpräfixe sind besonders:

SchlüsselBedeutung
nameAnzeigename in .help
_cls_docWas das Modul tut
_cmd_doc_<Befehl>Was dieser Befehl tut

Alles andere gehört dir und wird mit m.T abgerufen.

go
func (m *Weather) Strings() map[string]string {
	return map[string]string{
		"name":             "Weather",
		"_cls_doc":         "Aktuelles Wetter für eine Stadt",
		"_cmd_doc_weather": "[Stadt] — Wetter anzeigen",
		"no_city":          "❌ <b>Welche Stadt?</b>",
	}
}

Init

Läuft einmal bei der Registrierung, bevor irgendein Befehl auslösen kann. Base hat m.Client, m.DB und m.Translator zu diesem Zeitpunkt schon gefüllt — nutze Init also nur für deine eigene Einrichtung.

go
func (m *Weather) Init(client *goroku.CustomTelegramClient, db *goroku.Database) error {
	if err := m.Base.Init(client, db); err != nil {
		return err
	}
	m.cache = make(map[string]string)
	return nil
}

Rufe m.Base.Init zuerst auf

Der Loader füllt die Felder vor dem Init-Aufruf, im Normalbetrieb ist dieser Aufruf also überflüssig. Lass ihn trotzdem stehen: so funktioniert das Modul auch, wenn es in einem Test direkt erzeugt wird, ohne den Loader.

ClientReady

Läuft, sobald die Telegram-Verbindung steht. Für alles, was beim Start die API braucht; Init kann vor dem Verbindungsaufbau laufen.

go
func (m *Weather) ClientReady() error {
	me := m.Client.Me()
	_ = me
	return nil
}

OnUnload

Läuft, wenn das Modul entfernt wird. Gib hier Goroutinen, Timer und Dateihandles frei.

go
func (m *Weather) OnUnload() error {
	close(m.stop)
	return nil
}

WARNING

Ein Panic in OnUnload wird abgefangen und geloggt, das Modul wird aber trotzdem entfernt. Verlass dich für korrektheitskritische Aufräumarbeiten nicht auf OnUnload.

OnDlmod

Läuft direkt nach der Installation über .dlmod. Praktisch für eine einmalige Begrüßung oder Ersteinrichtung.

Watchers

Handler, die jede Nachricht sehen, nicht nur Befehle. Siehe Watcher.

Jenseits des Interface

Mehrere Fähigkeiten sind über eigene Interfaces optional — deklariere die Methode, und Goroku greift sie auf:

InterfaceMethodeZweck
ModuleWithMetaCommandMetas()Aliase und Einschränkungen
ModuleWithConfigSchemaConfigSchema()Typisierte Einstellungen
ModuleWithConfigReadyConfigReady(map[string]any)Auf Änderungen reagieren
ModuleWithTranslationAliasesTranslationAliases()Zusätzliche Namen für Übersetzungsdateien

Vollständige Liste unter Optionale Interfaces.

Released under the GNU AGPL v3 License.