хз
This commit is contained in:
parent
c22eba6f87
commit
ea6fb882f1
69
source/app.d
69
source/app.d
@ -5,18 +5,26 @@ import asdf: deserialize, serializeToJson;
|
||||
import util;
|
||||
|
||||
void main() {
|
||||
init("", "hot-chilli.im");
|
||||
import std.process: environment;
|
||||
alias env = environment.get;
|
||||
homeserver = env("SKUNKYBOT_HOMESERVER");
|
||||
init(env("SKUNKYBOT_TOKEN"));
|
||||
sync;
|
||||
}
|
||||
|
||||
HTTP http;
|
||||
string homeserver;
|
||||
void init(string token, string hs) {
|
||||
string syncUrl;
|
||||
string initialBatch;
|
||||
void init(string token) {
|
||||
http = HTTP();
|
||||
http.addRequestHeader("Authorization", "Bearer " ~ token);
|
||||
http.tcpNoDelay = true;
|
||||
homeserver = "https://" ~ hs;
|
||||
get(homeserver~"/_matrix/federation/v1/version");
|
||||
|
||||
// initial sync
|
||||
writeln("starting initial sync..");
|
||||
syncUrl = homeserver ~ "/_matrix/client/v3/sync?set_presence=online";
|
||||
initialBatch = (get(syncUrl, http).deserialize!Sync).next_batch; syncUrl ~= "&since=";
|
||||
writeln("done!");
|
||||
}
|
||||
|
||||
void send(T)(T content, string roomid, string type = "m.room.message") {
|
||||
@ -29,36 +37,55 @@ void send(T)(T content, string roomid, string type = "m.room.message") {
|
||||
// post(homeserver~"/_matrix/client/v3/rooms/"~roomid~"/join", http);
|
||||
// }
|
||||
|
||||
void sync() {
|
||||
import commands;
|
||||
static MSG helpgen() {
|
||||
string buf;
|
||||
static foreach (member; __traits(allMembers, commands)) {
|
||||
static foreach (attr; __traits(getAttributes, __traits(getMember, commands, member))) {
|
||||
static if (is(typeof(attr) == Command)) buf ~= member ~ ": " ~ attr.description ~ '\n';
|
||||
}
|
||||
}
|
||||
return MSG(buf);
|
||||
}
|
||||
|
||||
string str = homeserver ~ "/_matrix/client/v3/sync?set_presence=online";
|
||||
Sync content = get(str, http).deserialize!Sync; str ~= "&since=";
|
||||
void sync() {
|
||||
auto content = Sync();
|
||||
content.next_batch = initialBatch;
|
||||
for (;;) {
|
||||
string bthUrl = str ~ content.next_batch;
|
||||
content = get(bthUrl, http).deserialize!Sync;
|
||||
string bthUrl = syncUrl ~ content.next_batch;
|
||||
try content = get(bthUrl, http).deserialize!Sync;
|
||||
catch (Exception e) { writeln("ERR: ", e.msg); continue; }
|
||||
|
||||
foreach (room, _; content.rooms.invite) {
|
||||
writeln("Joining to room: ", room);
|
||||
post(homeserver~"/_matrix/client/v3/rooms/"~room~"/join", null, http);
|
||||
send(MSG("Привет, я СканкиБот"), room);
|
||||
send(MSG("Йа криведко"), room);
|
||||
}
|
||||
foreach (room, roomContent; content.rooms.join) {
|
||||
foreach(event; roomContent.timeline.events) {
|
||||
if (event.type == "m.room.message") {
|
||||
try {
|
||||
auto evt = deserialize!MSG(event.content.data);
|
||||
auto evt = deserialize!MSG(event.content.raw);
|
||||
if (!evt.body.length) break;
|
||||
auto argz = parseMsg(evt.body);
|
||||
|
||||
if (argz.command == "hlp") {
|
||||
send(helpgen, room);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (member; __traits(allMembers, commands)) {
|
||||
alias mmbr = __traits(getMember, commands, member);
|
||||
if (evt.body[1..$] == member) {
|
||||
static foreach (attr; __traits(getAttributes, mmbr)) {
|
||||
static if (is(attr == Command)) {
|
||||
static if (is(mmbr == function))
|
||||
send(mmbr(), room);
|
||||
else static if (__traits(isStaticArray, mmbr))
|
||||
send(MSG(mmbr[0], mmbr[1]), room);
|
||||
if (argz.command == member) {
|
||||
alias command = __traits(getMember, commands, member);
|
||||
foreach (attr; __traits(getAttributes, command)) {
|
||||
static if (is(typeof(attr) == Command)) {
|
||||
static if (is(typeof(command) == function))
|
||||
auto content = command(argz, &event);
|
||||
else static if (__traits(isStaticArray, command))
|
||||
auto content = MSG(command[0], command[1]);
|
||||
else
|
||||
send(MSG(mmbr), room);
|
||||
auto content = MSG(command);
|
||||
send(content, room);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,40 @@
|
||||
module commands;
|
||||
import util;
|
||||
enum Command; // UDA
|
||||
|
||||
// auto avatar(string[] arguments) @Command {
|
||||
// string url = cast(string)get(homeserver~"/_matrix/client/v3/profile/"~event.sender~"/avatar_url");
|
||||
// if (url == "{}")
|
||||
// return MSG("User has no avatar");
|
||||
// return MSG(event.sender, `<img src="`~url[15..$-2]~`">`);
|
||||
// }
|
||||
// UDA
|
||||
struct Command {
|
||||
string description = "No description provided";
|
||||
string name;
|
||||
}
|
||||
|
||||
@Command string[2] huy = [":orehussmile:",
|
||||
@Command("Отображает аватар пользователя")
|
||||
auto avatar(Arguments argz, EventWithoutRoomID* evt) {
|
||||
import std.net.curl: get;
|
||||
string url = cast(string)get(homeserver~"/_matrix/client/v3/profile/" ~
|
||||
((argz.parsed.length == 0) ? evt.sender : argz.parsed[0]) ~ "/avatar_url");
|
||||
if (url == "{}") return MSG("User has no avatar");
|
||||
return MSG(evt.sender, `<img src="`~url[15..$-2]~`">`);
|
||||
}
|
||||
|
||||
@Command("", "пинг")
|
||||
auto ping(Arguments, EventWithoutRoomID* evt) {
|
||||
import std.datetime: Clock, SysTime, unixTimeToStdTime;
|
||||
auto delay = (Clock.currTime() - SysTime(unixTimeToStdTime(0))).total!"msecs" - evt.origin_server_ts;
|
||||
return MSG("PONG [" ~ intToStr(delay) ~ " ms]");
|
||||
}
|
||||
|
||||
@Command("хз мне лень делать описание")
|
||||
auto echo(Arguments argz, EventWithoutRoomID* evt) {
|
||||
return MSG((argz.raw.length > 6) ? argz.raw[6..$] : "Too small MSG");
|
||||
}
|
||||
|
||||
@Command()
|
||||
string[2] huy = [":orehussmile:",
|
||||
`<img data-mx-emoticon height="32" alt=":orehussmile:" title=":orehussmile:"
|
||||
src="mxc://4d2.org/XvWYAuhASYRHtYvtspsrWvtU" >`];
|
||||
@Command string ver = "SkunkyBot Pre-Alpha 0.1 :: https://git.bloat.cat/skunky/skunkybot-d";
|
||||
static @Command string compver = "Compiler version: "~intToStr(__VERSION__);
|
||||
|
||||
// switch (evt.body) {
|
||||
// case "!huy":
|
||||
// send(MSG(":orehussmile:",
|
||||
// ), room);
|
||||
// break;
|
||||
// case "!версия": send(), room); break;
|
||||
// case "скунс": send(MSG("еблан"), room); break;
|
||||
// case "!avatar":
|
||||
//
|
||||
// break;
|
||||
// default: break;
|
||||
// }
|
||||
@Command("Версия бота", "версия")
|
||||
string ver = "SkunkyBot Pre-Alpha 0.1 :: https://git.bloat.cat/skunky/skunkybot-d";
|
||||
|
||||
@Command("test")
|
||||
static string compver = "Compiler version: "~intToStr(__VERSION__);
|
@ -1,6 +1,8 @@
|
||||
module util;
|
||||
import asdf;
|
||||
|
||||
string homeserver;
|
||||
|
||||
string intToStr(T)(T num) {
|
||||
char[] buf;
|
||||
for(short i; num > 0; ++i) {
|
||||
@ -11,10 +13,10 @@ string intToStr(T)(T num) {
|
||||
|
||||
struct JsonObject {
|
||||
import mir.conv: to;
|
||||
string data;
|
||||
string raw;
|
||||
|
||||
SerdeException deserializeFromAsdf(Asdf data) {
|
||||
this.data = data.to!string;
|
||||
this.raw = data.to!string;
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -24,6 +26,14 @@ struct JsonObject {
|
||||
}
|
||||
}
|
||||
|
||||
struct EventWithoutRoomID {
|
||||
JsonObject content;
|
||||
string event_id;
|
||||
ulong origin_server_ts;
|
||||
@serdeOptional string sender, state_key, type;
|
||||
// Unsigned unsigned;
|
||||
}
|
||||
|
||||
struct Sync {
|
||||
struct StrippedStateEvent {
|
||||
JsonObject content;
|
||||
@ -42,14 +52,6 @@ struct Sync {
|
||||
}
|
||||
struct Joined {
|
||||
struct Timeline {
|
||||
struct EventWithoutRoomID {
|
||||
JsonObject content;
|
||||
string event_id;
|
||||
ulong origin_server_ts;
|
||||
@serdeOptional string sender, state_key, type;
|
||||
// Unsigned unsigned;
|
||||
}
|
||||
|
||||
EventWithoutRoomID[] events;
|
||||
bool limited;
|
||||
string prev_batch;
|
||||
@ -60,7 +62,7 @@ struct Sync {
|
||||
int notification_count;
|
||||
}
|
||||
|
||||
Timeline timeline;
|
||||
@serdeOptional Timeline timeline;
|
||||
UNC unread_notifications;
|
||||
}
|
||||
|
||||
@ -79,3 +81,41 @@ struct MSG {
|
||||
string msgtype = "m.notice";
|
||||
@serdeOptional string format = "org.matrix.custom.html";
|
||||
}
|
||||
|
||||
struct Arguments {
|
||||
string raw;
|
||||
string command;
|
||||
string[] parsed;
|
||||
string[string] options;
|
||||
}
|
||||
|
||||
auto parseMsg(string cmd) {
|
||||
Arguments argz = Arguments(cmd);
|
||||
if (argz.raw[0] == '#') {
|
||||
string buf;
|
||||
for (ulong i = 1; i < argz.raw.length; ++i)
|
||||
if (argz.raw[i] != ' ' && argz.raw[i] != '=') {
|
||||
buf ~= argz.raw[i];
|
||||
if (i+1 == argz.raw.length || (argz.raw[i+1] == ' ' || argz.raw[i+1] == '=')) {
|
||||
argz.parsed ~= buf;
|
||||
buf = null;
|
||||
}
|
||||
}
|
||||
argz.command = argz.parsed[0]; argz.parsed = argz.parsed[1..$];
|
||||
|
||||
for (ulong i; i < argz.parsed.length; ++i)
|
||||
if (argz.parsed[i][0] == '-') {
|
||||
string key = argz.parsed[i];
|
||||
auto val = (i+1 < argz.parsed.length && argz.parsed[i+1][0] != '-')
|
||||
? argz.parsed[i+1] : null;
|
||||
if (key[1] == '-') argz.options[key[2..$]] = val;
|
||||
else for (ulong x = 1; x < key.length; ++x)
|
||||
argz.options[key[x..x+1]] = val;
|
||||
|
||||
auto x = (val) ? i + 2 : i + 1;
|
||||
argz.parsed = argz.parsed[0..i] ~ argz.parsed[x..$];
|
||||
i = i - (x - i);
|
||||
}
|
||||
}
|
||||
return argz;
|
||||
}
|
Loading…
Reference in New Issue
Block a user