хз
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;
|
import util;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
init("", "hot-chilli.im");
|
import std.process: environment;
|
||||||
|
alias env = environment.get;
|
||||||
|
homeserver = env("SKUNKYBOT_HOMESERVER");
|
||||||
|
init(env("SKUNKYBOT_TOKEN"));
|
||||||
sync;
|
sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTP http;
|
HTTP http;
|
||||||
string homeserver;
|
string syncUrl;
|
||||||
void init(string token, string hs) {
|
string initialBatch;
|
||||||
|
void init(string token) {
|
||||||
http = HTTP();
|
http = HTTP();
|
||||||
http.addRequestHeader("Authorization", "Bearer " ~ token);
|
http.addRequestHeader("Authorization", "Bearer " ~ token);
|
||||||
http.tcpNoDelay = true;
|
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") {
|
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);
|
// post(homeserver~"/_matrix/client/v3/rooms/"~roomid~"/join", http);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
void sync() {
|
|
||||||
import commands;
|
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";
|
void sync() {
|
||||||
Sync content = get(str, http).deserialize!Sync; str ~= "&since=";
|
auto content = Sync();
|
||||||
|
content.next_batch = initialBatch;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
string bthUrl = str ~ content.next_batch;
|
string bthUrl = syncUrl ~ content.next_batch;
|
||||||
content = get(bthUrl, http).deserialize!Sync;
|
try content = get(bthUrl, http).deserialize!Sync;
|
||||||
|
catch (Exception e) { writeln("ERR: ", e.msg); continue; }
|
||||||
|
|
||||||
foreach (room, _; content.rooms.invite) {
|
foreach (room, _; content.rooms.invite) {
|
||||||
writeln("Joining to room: ", room);
|
writeln("Joining to room: ", room);
|
||||||
post(homeserver~"/_matrix/client/v3/rooms/"~room~"/join", null, http);
|
post(homeserver~"/_matrix/client/v3/rooms/"~room~"/join", null, http);
|
||||||
send(MSG("Привет, я СканкиБот"), room);
|
send(MSG("Йа криведко"), room);
|
||||||
}
|
}
|
||||||
foreach (room, roomContent; content.rooms.join) {
|
foreach (room, roomContent; content.rooms.join) {
|
||||||
foreach(event; roomContent.timeline.events) {
|
foreach(event; roomContent.timeline.events) {
|
||||||
if (event.type == "m.room.message") {
|
if (event.type == "m.room.message") {
|
||||||
try {
|
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)) {
|
foreach (member; __traits(allMembers, commands)) {
|
||||||
alias mmbr = __traits(getMember, commands, member);
|
if (argz.command == member) {
|
||||||
if (evt.body[1..$] == member) {
|
alias command = __traits(getMember, commands, member);
|
||||||
static foreach (attr; __traits(getAttributes, mmbr)) {
|
foreach (attr; __traits(getAttributes, command)) {
|
||||||
static if (is(attr == Command)) {
|
static if (is(typeof(attr) == Command)) {
|
||||||
static if (is(mmbr == function))
|
static if (is(typeof(command) == function))
|
||||||
send(mmbr(), room);
|
auto content = command(argz, &event);
|
||||||
else static if (__traits(isStaticArray, mmbr))
|
else static if (__traits(isStaticArray, command))
|
||||||
send(MSG(mmbr[0], mmbr[1]), room);
|
auto content = MSG(command[0], command[1]);
|
||||||
else
|
else
|
||||||
send(MSG(mmbr), room);
|
auto content = MSG(command);
|
||||||
|
send(content, room);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,40 @@
|
|||||||
module commands;
|
module commands;
|
||||||
import util;
|
import util;
|
||||||
enum Command; // UDA
|
|
||||||
|
|
||||||
// auto avatar(string[] arguments) @Command {
|
// UDA
|
||||||
// string url = cast(string)get(homeserver~"/_matrix/client/v3/profile/"~event.sender~"/avatar_url");
|
struct Command {
|
||||||
// if (url == "{}")
|
string description = "No description provided";
|
||||||
// return MSG("User has no avatar");
|
string name;
|
||||||
// return MSG(event.sender, `<img src="`~url[15..$-2]~`">`);
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
@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:"
|
`<img data-mx-emoticon height="32" alt=":orehussmile:" title=":orehussmile:"
|
||||||
src="mxc://4d2.org/XvWYAuhASYRHtYvtspsrWvtU" >`];
|
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) {
|
@Command("Версия бота", "версия")
|
||||||
// case "!huy":
|
string ver = "SkunkyBot Pre-Alpha 0.1 :: https://git.bloat.cat/skunky/skunkybot-d";
|
||||||
// send(MSG(":orehussmile:",
|
|
||||||
// ), room);
|
@Command("test")
|
||||||
// break;
|
static string compver = "Compiler version: "~intToStr(__VERSION__);
|
||||||
// case "!версия": send(), room); break;
|
|
||||||
// case "скунс": send(MSG("еблан"), room); break;
|
|
||||||
// case "!avatar":
|
|
||||||
//
|
|
||||||
// break;
|
|
||||||
// default: break;
|
|
||||||
// }
|
|
@ -1,6 +1,8 @@
|
|||||||
module util;
|
module util;
|
||||||
import asdf;
|
import asdf;
|
||||||
|
|
||||||
|
string homeserver;
|
||||||
|
|
||||||
string intToStr(T)(T num) {
|
string intToStr(T)(T num) {
|
||||||
char[] buf;
|
char[] buf;
|
||||||
for(short i; num > 0; ++i) {
|
for(short i; num > 0; ++i) {
|
||||||
@ -11,10 +13,10 @@ string intToStr(T)(T num) {
|
|||||||
|
|
||||||
struct JsonObject {
|
struct JsonObject {
|
||||||
import mir.conv: to;
|
import mir.conv: to;
|
||||||
string data;
|
string raw;
|
||||||
|
|
||||||
SerdeException deserializeFromAsdf(Asdf data) {
|
SerdeException deserializeFromAsdf(Asdf data) {
|
||||||
this.data = data.to!string;
|
this.raw = data.to!string;
|
||||||
return null;
|
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 Sync {
|
||||||
struct StrippedStateEvent {
|
struct StrippedStateEvent {
|
||||||
JsonObject content;
|
JsonObject content;
|
||||||
@ -42,14 +52,6 @@ struct Sync {
|
|||||||
}
|
}
|
||||||
struct Joined {
|
struct Joined {
|
||||||
struct Timeline {
|
struct Timeline {
|
||||||
struct EventWithoutRoomID {
|
|
||||||
JsonObject content;
|
|
||||||
string event_id;
|
|
||||||
ulong origin_server_ts;
|
|
||||||
@serdeOptional string sender, state_key, type;
|
|
||||||
// Unsigned unsigned;
|
|
||||||
}
|
|
||||||
|
|
||||||
EventWithoutRoomID[] events;
|
EventWithoutRoomID[] events;
|
||||||
bool limited;
|
bool limited;
|
||||||
string prev_batch;
|
string prev_batch;
|
||||||
@ -60,7 +62,7 @@ struct Sync {
|
|||||||
int notification_count;
|
int notification_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
Timeline timeline;
|
@serdeOptional Timeline timeline;
|
||||||
UNC unread_notifications;
|
UNC unread_notifications;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,3 +81,41 @@ struct MSG {
|
|||||||
string msgtype = "m.notice";
|
string msgtype = "m.notice";
|
||||||
@serdeOptional string format = "org.matrix.custom.html";
|
@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