Add message sending, adding docs
This commit is contained in:
parent
4f2da16910
commit
efbba335a7
7 changed files with 119 additions and 51 deletions
|
@ -17,3 +17,10 @@ main() {
|
||||||
- id: String
|
- id: String
|
||||||
- token: String
|
- token: String
|
||||||
url overrides id and token
|
url overrides id and token
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
We took inspiration from [discord.js](https://github.com/discordjs/discord.js) and [Grapes-discord.grapes](https://github.com/BlackdestinyXX/Grapes-discord.grapes).
|
||||||
|
|
||||||
|
### Packages
|
||||||
|
- [http](https://pub.dev/packages/http) by dart.dev (BSD-3-Clause)
|
||||||
|
- [events-emitter](https://pub.dev/packages/events_emitter) by drafakiller.com (MIT)
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
import 'package:http/http.dart';
|
|
||||||
|
|
||||||
void handleCode(Response res) async {
|
|
||||||
int code = res.statusCode;
|
|
||||||
switch (code) {
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
|
@ -1,15 +1,17 @@
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
import "dart:io";
|
import "dart:io";
|
||||||
import "package:tn_discord/src/types.dart";
|
|
||||||
|
|
||||||
import "requests.dart";
|
|
||||||
|
|
||||||
import "dart:convert";
|
import "dart:convert";
|
||||||
import "package:events_emitter/events_emitter.dart";
|
import "package:events_emitter/events_emitter.dart";
|
||||||
|
|
||||||
|
import "types.dart";
|
||||||
|
import "requests.dart";
|
||||||
|
|
||||||
final version = "10";
|
final version = "10";
|
||||||
final apiURL = "https://discord.com/api/v$version";
|
final apiURL = "https://discord.com/api/v$version";
|
||||||
|
|
||||||
|
/// This function calculate the intent number required from the gateway.
|
||||||
|
/// [intents] is a list of multiples of two. You can use GatewayIntentBits class.
|
||||||
|
/// Return a number.
|
||||||
int calculateIntents(List<int> intents) {
|
int calculateIntents(List<int> intents) {
|
||||||
int intentsNumber = 0;
|
int intentsNumber = 0;
|
||||||
|
|
||||||
|
@ -20,6 +22,8 @@ int calculateIntents(List<int> intents) {
|
||||||
return intentsNumber;
|
return intentsNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// The main hub for interacting with the Discord API, and the starting point for any bot.
|
||||||
class Client extends EventEmitter {
|
class Client extends EventEmitter {
|
||||||
String? token;
|
String? token;
|
||||||
int intents;
|
int intents;
|
||||||
|
@ -29,8 +33,13 @@ class Client extends EventEmitter {
|
||||||
dynamic guilds;
|
dynamic guilds;
|
||||||
dynamic ready;
|
dynamic ready;
|
||||||
|
|
||||||
|
/// Create a new Client.
|
||||||
|
/// [intents] Intents to enable for this connection, it's a multiple of two.
|
||||||
Client({this.intents = 0});
|
Client({this.intents = 0});
|
||||||
|
|
||||||
|
/// Logs the client in, establishing a WebSocket connection to Discord.
|
||||||
|
/// [token] is the token of the account to log in with.
|
||||||
|
/// Get the token from https://discord.dev
|
||||||
login(String token) async {
|
login(String token) async {
|
||||||
final websocket = await requestWebSocketURL();
|
final websocket = await requestWebSocketURL();
|
||||||
|
|
||||||
|
@ -44,7 +53,7 @@ class Client extends EventEmitter {
|
||||||
"token": token,
|
"token": token,
|
||||||
"intents": intents,
|
"intents": intents,
|
||||||
"properties": {
|
"properties": {
|
||||||
"os": "linux",
|
"os": Platform.operatingSystem,
|
||||||
"browser": "tn_discord",
|
"browser": "tn_discord",
|
||||||
"device": "tn_discord",
|
"device": "tn_discord",
|
||||||
},
|
},
|
||||||
|
@ -81,10 +90,10 @@ class Client extends EventEmitter {
|
||||||
List<Guild> gg = [];
|
List<Guild> gg = [];
|
||||||
|
|
||||||
for (dynamic g in i) {
|
for (dynamic g in i) {
|
||||||
gg.add(Guild(g));
|
gg.add(Guild(sender, g));
|
||||||
}
|
}
|
||||||
|
|
||||||
guilds = GuildManager(gg);
|
guilds = GuildManager(sender, gg);
|
||||||
|
|
||||||
int n = i.length;
|
int n = i.length;
|
||||||
|
|
||||||
|
@ -112,7 +121,7 @@ class Client extends EventEmitter {
|
||||||
sessionID = event["d"]["session_id"];
|
sessionID = event["d"]["session_id"];
|
||||||
break;
|
break;
|
||||||
case "GUILD_CREATE":
|
case "GUILD_CREATE":
|
||||||
guilds.cache.set(event["d"]["id"], Guild(event["d"]));
|
guilds.cache.set(event["d"]["id"], Guild(sender, event["d"]));
|
||||||
if (n > 1) {
|
if (n > 1) {
|
||||||
n--;
|
n--;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'main.dart';
|
import 'main.dart';
|
||||||
|
import 'types.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
@ -34,13 +35,13 @@ Future<String> requestWebSocketURL() async {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Sender {
|
class Sender {
|
||||||
String? token;
|
final String? _token;
|
||||||
Map<String, String> headers = {};
|
Map<String, String> headers = {};
|
||||||
|
|
||||||
Sender(token) {
|
Sender(this._token) {
|
||||||
headers = {
|
headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Authorization": "Bot $token"
|
"Authorization": "Bot $_token",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,4 +51,29 @@ class Sender {
|
||||||
res = json.decode(res.body);
|
res = json.decode(res.body);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future send(Message msg, String cid) async {
|
||||||
|
final url = Uri.parse("$apiURL/channels/$cid/messages");
|
||||||
|
dynamic res = await http.post(url, headers: headers, body: json.encode(msg.exportable()));
|
||||||
|
res = json.decode(res.body);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future fetchGuild(String id) async {
|
||||||
|
dynamic res = await http.get(Uri.parse("$apiURL/guilds/$id"), headers: headers);
|
||||||
|
if (res.statusCode != 200) {
|
||||||
|
throw Exception("Error ${res.statusCode} receiving the guild");
|
||||||
|
}
|
||||||
|
res = json.decode(res.body);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future fetchChannel(String id) async {
|
||||||
|
dynamic res = await http.get(Uri.parse("$apiURL/channels/$id"), headers: headers);
|
||||||
|
if (res.statusCode != 200) {
|
||||||
|
throw Exception("Error ${res.statusCode} receiving the channel");
|
||||||
|
}
|
||||||
|
res = json.decode(res.body);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,9 @@
|
||||||
import "dart:convert";
|
import "dart:convert";
|
||||||
import "package:http/http.dart" as http;
|
import "package:http/http.dart" as http;
|
||||||
import "main.dart";
|
import "main.dart";
|
||||||
|
import "requests.dart";
|
||||||
|
|
||||||
|
/// A list of all Gateway Intents Bits.
|
||||||
class GatewayIntentBits {
|
class GatewayIntentBits {
|
||||||
static const Guilds = 1;
|
static const Guilds = 1;
|
||||||
static const GuildMembers = 2;
|
static const GuildMembers = 2;
|
||||||
|
@ -25,15 +27,20 @@ class GatewayIntentBits {
|
||||||
static const AutoModerationExecution = 2097152;
|
static const AutoModerationExecution = 2097152;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A collection of variables. Like NodeJS' Map and discordjs' Collections
|
||||||
|
/// This will be moved to a separate package in the future.
|
||||||
class Collection {
|
class Collection {
|
||||||
final Map<String, dynamic> _variables = {};
|
final Map<String, dynamic> _variables = {};
|
||||||
|
/// Create a new Collection
|
||||||
Collection();
|
Collection();
|
||||||
|
|
||||||
|
/// Adds a new element with key [key] and value [value] to the Map. If an element with the same key already exists, the element will be updated.
|
||||||
dynamic set(String key, dynamic value) {
|
dynamic set(String key, dynamic value) {
|
||||||
_variables[key] = value;
|
_variables[key] = value;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns [key] from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.
|
||||||
dynamic get(String key) {
|
dynamic get(String key) {
|
||||||
if (_variables[key] == null) {
|
if (_variables[key] == null) {
|
||||||
throw Exception("Variable not found for $key");
|
throw Exception("Variable not found for $key");
|
||||||
|
@ -41,43 +48,56 @@ class Collection {
|
||||||
return _variables[key];
|
return _variables[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes [key] from the Map object.
|
||||||
void remove(String key) {
|
void remove(String key) {
|
||||||
_variables.remove(key);
|
_variables.remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Alias of [remove]
|
||||||
|
void delete(String key) {
|
||||||
|
remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sum to the value of [key] to [value].
|
||||||
dynamic add(String key, num value) {
|
dynamic add(String key, num value) {
|
||||||
_variables[key] += value;
|
_variables[key] += value;
|
||||||
return value + _variables[key];
|
return value + _variables[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Subtract [value] from the value of [key].
|
||||||
dynamic subtract(String key, num value) {
|
dynamic subtract(String key, num value) {
|
||||||
_variables[key] -= value;
|
_variables[key] -= value;
|
||||||
return value - _variables[key];
|
return _variables[key] - value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns all the variables as a Map.
|
||||||
Map<String, dynamic> getAll() {
|
Map<String, dynamic> getAll() {
|
||||||
return _variables;
|
return _variables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns all the variables' keys as a List.
|
||||||
List<String> keys() {
|
List<String> keys() {
|
||||||
return _variables.keys.toList();
|
return _variables.keys.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns all the variables' values as a List.
|
||||||
List<dynamic> values() {
|
List<dynamic> values() {
|
||||||
return _variables.values.toList();
|
return _variables.values.toList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a guild (aka server) on Discord.
|
||||||
class Guild {
|
class Guild {
|
||||||
String id = '';
|
String id = '';
|
||||||
String name = '';
|
String name = '';
|
||||||
String? owner;
|
String? owner;
|
||||||
String? description;
|
String? description;
|
||||||
ChannelManager channels = ChannelManager([]);
|
late ChannelManager channels;
|
||||||
MemberManager members = MemberManager([], '');
|
late MemberManager members;
|
||||||
RoleManager roles = RoleManager([]);
|
late RoleManager roles;
|
||||||
|
final Sender _sender;
|
||||||
|
|
||||||
Guild(Map data) {
|
Guild(this._sender, Map data) {
|
||||||
id = data["id"];
|
id = data["id"];
|
||||||
name = data["name"];
|
name = data["name"];
|
||||||
description = data["description"];
|
description = data["description"];
|
||||||
|
@ -86,9 +106,9 @@ class Guild {
|
||||||
if(data["channels"] != null && data["members"] != null && data["roles"] != null) {
|
if(data["channels"] != null && data["members"] != null && data["roles"] != null) {
|
||||||
List<Channel> cc = [];
|
List<Channel> cc = [];
|
||||||
for (var c in data["channels"]) {
|
for (var c in data["channels"]) {
|
||||||
cc.add(Channel(c));
|
cc.add(Channel(_sender, c));
|
||||||
}
|
}
|
||||||
channels = ChannelManager(cc);
|
channels = ChannelManager(_sender, cc);
|
||||||
|
|
||||||
List<Member> mm = [];
|
List<Member> mm = [];
|
||||||
for (var m in data["members"]) {
|
for (var m in data["members"]) {
|
||||||
|
@ -101,25 +121,27 @@ class Guild {
|
||||||
rr.add(Role(r));
|
rr.add(Role(r));
|
||||||
}
|
}
|
||||||
roles = RoleManager(rr);
|
roles = RoleManager(rr);
|
||||||
|
} else {
|
||||||
|
channels = ChannelManager(_sender, []);
|
||||||
|
members = MemberManager([], id);
|
||||||
|
roles = RoleManager([]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GuildManager {
|
class GuildManager {
|
||||||
final Collection cache = Collection();
|
final Collection cache = Collection();
|
||||||
|
final Sender _sender;
|
||||||
|
|
||||||
GuildManager(List<Guild> guilds) {
|
GuildManager(this._sender, List<Guild> guilds) {
|
||||||
for (var guild in guilds) {
|
for (var guild in guilds) {
|
||||||
cache.set(guild.id, guild);
|
cache.set(guild.id, guild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Guild> fetch(String id) async {
|
Future<Guild> fetch(String id) async {
|
||||||
var res = await http.get(Uri.parse("$apiURL/guilds/$id"));
|
var res = await _sender.fetchGuild(id);
|
||||||
if (res.statusCode != 200) {
|
final guild = Guild(_sender, res);
|
||||||
throw Exception("Error ${res.statusCode} receiving the guild");
|
|
||||||
}
|
|
||||||
final guild = Guild(json.decode(res.body));
|
|
||||||
cache.set(guild.id, guild);
|
cache.set(guild.id, guild);
|
||||||
return guild;
|
return guild;
|
||||||
}
|
}
|
||||||
|
@ -128,28 +150,32 @@ class GuildManager {
|
||||||
class Channel {
|
class Channel {
|
||||||
String id = '';
|
String id = '';
|
||||||
String name = '';
|
String name = '';
|
||||||
|
final Sender _sender;
|
||||||
|
|
||||||
Channel(Map data) {
|
Channel(this._sender, data) {
|
||||||
id = data["id"];
|
id = data["id"];
|
||||||
name = data["name"];
|
name = data["name"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<MessageSent> send(Message message) async {
|
||||||
|
await _sender.send(message, id);
|
||||||
|
return MessageSent(message, id: id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChannelManager {
|
class ChannelManager {
|
||||||
final Collection cache = Collection();
|
final Collection cache = Collection();
|
||||||
|
final Sender _sender;
|
||||||
|
|
||||||
ChannelManager(List<Channel> channels) {
|
ChannelManager(this._sender, List<Channel> channels) {
|
||||||
for (var channel in channels) {
|
for (var channel in channels) {
|
||||||
cache.set(channel.id, channel);
|
cache.set(channel.id, channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Channel> fetch(String id) async {
|
Future<Channel> fetch(String id) async {
|
||||||
var res = await http.get(Uri.parse("$apiURL/channels/$id"));
|
var res = await _sender.fetchChannel(id);
|
||||||
if (res.statusCode != 200) {
|
dynamic channel = Channel(_sender, res);
|
||||||
throw Exception("Error ${res.statusCode} receiving the channel");
|
|
||||||
}
|
|
||||||
dynamic channel = Channel(json.decode(res.body));
|
|
||||||
cache.set(channel.id, channel);
|
cache.set(channel.id, channel);
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
@ -157,12 +183,10 @@ class ChannelManager {
|
||||||
|
|
||||||
class Member {
|
class Member {
|
||||||
String id = '';
|
String id = '';
|
||||||
String name = '';
|
|
||||||
User user = User({});
|
User user = User({});
|
||||||
|
|
||||||
Member(Map data) {
|
Member(Map data) {
|
||||||
id = data["user"]["id"];
|
id = data["user"]["id"];
|
||||||
name = data["user"]["username"];
|
|
||||||
user = User(data["user"]);
|
user = User(data["user"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,4 +277,23 @@ class UserManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef Embed = Map<String, String>;
|
typedef Embed = Map<String, String>;
|
||||||
typedef Message = Map<String, String>;
|
|
||||||
|
/// Represents a message on Discord.
|
||||||
|
class Message {
|
||||||
|
String? content;
|
||||||
|
Message({ this.content });
|
||||||
|
|
||||||
|
exportable() {
|
||||||
|
return {
|
||||||
|
"content": content,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a sent message on Discord.
|
||||||
|
class MessageSent extends Message {
|
||||||
|
String id = '';
|
||||||
|
MessageSent(Message msg, { required this.id }) {
|
||||||
|
content = msg.content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import "dart:convert";
|
import "dart:convert";
|
||||||
|
|
||||||
import "package:http/http.dart";
|
import "package:http/http.dart";
|
||||||
import "error_handler.dart";
|
|
||||||
import 'requests.dart';
|
import 'requests.dart';
|
||||||
import "types.dart";
|
import "types.dart";
|
||||||
import "util.dart";
|
import "util.dart";
|
||||||
|
@ -25,7 +24,6 @@ class WebhookClient {
|
||||||
Map<String, String> body = {"content": content};
|
Map<String, String> body = {"content": content};
|
||||||
Response res = await sendWH(body, token, id);
|
Response res = await sendWH(body, token, id);
|
||||||
|
|
||||||
handleCode(res);
|
|
||||||
return json.decode(res.body);
|
return json.decode(res.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +33,6 @@ class WebhookClient {
|
||||||
|
|
||||||
Response res = await sendWH(body, token, id);
|
Response res = await sendWH(body, token, id);
|
||||||
|
|
||||||
handleCode(res);
|
|
||||||
return json.decode(res.body);
|
return json.decode(res.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +40,6 @@ class WebhookClient {
|
||||||
Map<String, String> body = {"content": content};
|
Map<String, String> body = {"content": content};
|
||||||
Response res = await editWH(body, token, this.id, id);
|
Response res = await editWH(body, token, this.id, id);
|
||||||
|
|
||||||
handleCode(res);
|
|
||||||
return json.decode(res.body);
|
return json.decode(res.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,20 +47,17 @@ class WebhookClient {
|
||||||
Map body = {"content": content, "embeds": embeds};
|
Map body = {"content": content, "embeds": embeds};
|
||||||
Response res = await editWH(body, token, this.id, id);
|
Response res = await editWH(body, token, this.id, id);
|
||||||
|
|
||||||
handleCode(res);
|
|
||||||
return json.decode(res.body);
|
return json.decode(res.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> get(String id) async {
|
Future<Map<String, dynamic>> get(String id) async {
|
||||||
Response res = await getWH(token, this.id, id);
|
Response res = await getWH(token, this.id, id);
|
||||||
handleCode(res);
|
|
||||||
|
|
||||||
return json.decode(res.body);
|
return json.decode(res.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> delete(String id) async {
|
Future<Map<String, dynamic>> delete(String id) async {
|
||||||
Response res = await deleteWH(token, this.id, id);
|
Response res = await deleteWH(token, this.id, id);
|
||||||
handleCode(res);
|
|
||||||
|
|
||||||
return json.decode(res.body);
|
return json.decode(res.body);
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue